From patchwork Tue Oct 13 15:46:22 2015
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Pavel Fedin
X-Patchwork-Id: 7386381
Return-Path:
X-Original-To: patchwork-kvm@patchwork.kernel.org
Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org
Received: from mail.kernel.org (mail.kernel.org [198.145.29.136])
by patchwork1.web.kernel.org (Postfix) with ESMTP id 6EDA39F1B9
for ;
Tue, 13 Oct 2015 15:46:51 +0000 (UTC)
Received: from mail.kernel.org (localhost [127.0.0.1])
by mail.kernel.org (Postfix) with ESMTP id 6134520749
for ;
Tue, 13 Oct 2015 15:46:50 +0000 (UTC)
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
by mail.kernel.org (Postfix) with ESMTP id CA50820748
for ;
Tue, 13 Oct 2015 15:46:48 +0000 (UTC)
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S932737AbbJMPqa (ORCPT
);
Tue, 13 Oct 2015 11:46:30 -0400
Received: from mailout3.w1.samsung.com ([210.118.77.13]:30043 "EHLO
mailout3.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
with ESMTP id S932668AbbJMPq1 (ORCPT );
Tue, 13 Oct 2015 11:46:27 -0400
Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244])
by mailout3.w1.samsung.com
(Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5
2014)) with ESMTP id <0NW6007JP15CAN70@mailout3.w1.samsung.com> for
kvm@vger.kernel.org; Tue, 13 Oct 2015 16:46:24 +0100 (BST)
X-AuditID: cbfec7f4-f79c56d0000012ee-4f-561d27501ff8
Received: from eusync1.samsung.com ( [203.254.199.211])
by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id BB.58.04846.0572D165;
Tue, 13 Oct 2015 16:46:24 +0100 (BST)
Received: from fedinw7x64 ([106.109.131.169])
by eusync1.samsung.com (Oracle Communications Messaging Server
7.0.5.31.0 64bit (built May 5 2014))
with ESMTPA id <0NW6000EF15AXP60@eusync1.samsung.com>; Tue,
13 Oct 2015 16:46:23 +0100 (BST)
From: Pavel Fedin
To: 'Andre Przywara' , marc.zyngier@arm.com,
christoffer.dall@linaro.org
Cc: eric.auger@linaro.org, kvmarm@lists.cs.columbia.edu,
linux-arm-kernel@lists.infradead.org, kvm@vger.kernel.org
References: <1444229726-31559-1-git-send-email-andre.przywara@arm.com>
In-reply-to: <1444229726-31559-1-git-send-email-andre.przywara@arm.com>
Subject: RE: [PATCH v3 00/16] KVM: arm64: GICv3 ITS emulation
Date: Tue, 13 Oct 2015 18:46:22 +0300
Message-id: <017001d105ce$5047a710$f0d6f530$@samsung.com>
MIME-version: 1.0
Content-type: text/plain; charset=us-ascii
Content-transfer-encoding: 7bit
X-Mailer: Microsoft Outlook 14.0
Thread-index: AQGpwlQ1jT6IOtVddOk+jpo6YGj/bJ64F2EQ
Content-language: ru
X-Brightmail-Tracker:
H4sIAAAAAAAAA+NgFvrDLMWRmVeSWpSXmKPExsVy+t/xy7oB6rJhBhP3MFmsmPeT0eLF63+M
FvO3nGG1mDO10OLjqePsFpseX2O1+HvnH5sDu8eaeWsYPe5c28PmcX7TGmaPzUvqPT5vkgtg
jeKySUnNySxLLdK3S+DKePyzlbFgsmHFhd7YBsZvGl2MnBwSAiYSx141MULYYhIX7q1n62Lk
4hASWMoo8ev+TLCEkMB3RoldG51AbDYBdYnTXz+wgNgiAkkS3U3vWEFsZoESicYvV9kg6t0k
7q8+wQxicwq4S+z4/o0dxBYWsJVYcegUWC+LgKrExzXHwGp4BSwl2vu/sUHYghI/Jt9jgZip
JbF+53EmCFteYvOat8wQhypI7Dj7mhHiBiOJW7vOs0PUiEhM+3ePeQKj0Cwko2YhGTULyahZ
SFoWMLKsYhRNLU0uKE5KzzXUK07MLS7NS9dLzs/dxAiJky87GBcfszrEKMDBqMTD+yJSJkyI
NbGsuDL3EKMEB7OSCG9SC1CINyWxsiq1KD++qDQntfgQozQHi5I479xd70OEBNITS1KzU1ML
UotgskwcnFINjMJqM5b8vMPzc4Zf872ohgds5iL6P62iFU645iQpqe5mmF/gKOyWG+e3+PUN
wYtvJzTqch/cVPrCompmQt/LTcLLZS1VPxrfUZH/eef5/iMy55LtfDcH53vvnG4xMXC+hsSi
l9P/mr6unbM97MdR5a43eS153i5XlntN/ua+u222Vt6r25ujXimxFGckGmoxFxUnAgBrT1OQ
jwIAAA==
Sender: kvm-owner@vger.kernel.org
Precedence: bulk
List-ID:
X-Mailing-List: kvm@vger.kernel.org
X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI,
T_RP_MATCHES_RCVD,
UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1
X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org
X-Virus-Scanned: ClamAV using ClamSMTP
Hello!
I already suggested one bunch of fixes on top of vITS series, and here is another one. It reconciles it with spurious interrupt
fix, and adds missing check in vgic_retire_disabled_irqs(), which was removed in original v3 series.
---
From bdbedc35a4dc9bc258b21792cf734aa3b2383dff Mon Sep 17 00:00:00 2001
From: Pavel Fedin
Date: Tue, 13 Oct 2015 15:24:19 +0300
Subject: [PATCH] KVM: arm/arm64: Fix LPI loss
compute_pending_for_cpu() should return true if there's something pending
on the given vCPU. This is used in order to correctly set
dist->irq_pending_on_cpu flag. However, the function knows nothing about
LPIs, this can contribute to LPI loss.
This patch fixes it by introducing vits_check_lpis() function, which
returns true if there's any pending LPI. Also, some refactoring done,
wrapping some repeated checks into helper functions.
Additionally, vgic_retire_disabled_irqs() is fixed to correctly skip LPIs.
Signed-off-by: Pavel Fedin
---
include/kvm/arm_vgic.h | 1 +
virt/kvm/arm/its-emul.c | 46 +++++++++++++++++++++++++++++++++++----------
virt/kvm/arm/its-emul.h | 1 +
virt/kvm/arm/vgic-v3-emul.c | 1 +
virt/kvm/arm/vgic.c | 19 +++++++++++++++++--
5 files changed, 56 insertions(+), 12 deletions(-)
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 39113b9..21c8427 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -148,6 +148,7 @@ struct vgic_vm_ops {
int (*map_resources)(struct kvm *, const struct vgic_params *);
bool (*queue_lpis)(struct kvm_vcpu *);
void (*unqueue_lpi)(struct kvm_vcpu *, int irq);
+ bool (*check_lpis)(struct kvm_vcpu *);
int (*inject_msi)(struct kvm *, struct kvm_msi *);
};
diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index b1d61df..2fcd844 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -381,6 +381,18 @@ out_unlock:
return ret;
}
+static bool its_is_enabled(struct kvm *kvm)
+{
+ return vgic_has_its(kvm) && kvm->arch.vgic.its.enabled &&
+ kvm->arch.vgic.lpis_enabled;
+}
+
+static bool lpi_is_pending(struct its_itte *itte, u32 vcpu_id)
+{
+ return itte->enabled && test_bit(vcpu_id, itte->pending) &&
+ itte->collection && (itte->collection->target_addr == vcpu_id);
+}
+
/*
* Find all enabled and pending LPIs and queue them into the list
* registers.
@@ -393,20 +405,12 @@ bool vits_queue_lpis(struct kvm_vcpu *vcpu)
struct its_itte *itte;
bool ret = true;
- if (!vgic_has_its(vcpu->kvm))
- return true;
- if (!its->enabled || !vcpu->kvm->arch.vgic.lpis_enabled)
+ if (!its_is_enabled(vcpu->kvm))
return true;
spin_lock(&its->lock);
for_each_lpi(device, itte, vcpu->kvm) {
- if (!itte->enabled || !test_bit(vcpu->vcpu_id, itte->pending))
- continue;
-
- if (!itte->collection)
- continue;
-
- if (itte->collection->target_addr != vcpu->vcpu_id)
+ if (!lpi_is_pending(itte, vcpu->vcpu_id))
continue;
@@ -436,6 +440,28 @@ void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi)
spin_unlock(&its->lock);
}
+bool vits_check_lpis(struct kvm_vcpu *vcpu)
+{
+ struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
+ struct its_device *device;
+ struct its_itte *itte;
+ bool ret = false;
+
+ if (!its_is_enabled(vcpu->kvm))
+ return false;
+
+ spin_lock(&its->lock);
+ for_each_lpi(device, itte, vcpu->kvm) {
+ ret = lpi_is_pending(itte, vcpu->vcpu_id);
+ if (ret)
+ goto out;
+ }
+
+out:
+ spin_unlock(&its->lock);
+ return ret;
+}
+
static void its_free_itte(struct its_itte *itte)
{
list_del(&itte->itte_list);
diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
index 236f153..f7fa5f8 100644
--- a/virt/kvm/arm/its-emul.h
+++ b/virt/kvm/arm/its-emul.h
@@ -41,6 +41,7 @@ int vits_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
bool vits_queue_lpis(struct kvm_vcpu *vcpu);
void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int irq);
+bool vits_check_lpis(struct kvm_vcpu *vcpu);
#define E_ITS_MOVI_UNMAPPED_INTERRUPT 0x010107
#define E_ITS_MOVI_UNMAPPED_COLLECTION 0x010109
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index 798f256..25463d0 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -966,6 +966,7 @@ void vgic_v3_init_emulation(struct kvm *kvm)
dist->vm_ops.inject_msi = vits_inject_msi;
dist->vm_ops.queue_lpis = vits_queue_lpis;
dist->vm_ops.unqueue_lpi = vits_unqueue_lpi;
+ dist->vm_ops.check_lpis = vits_check_lpis;
dist->vgic_dist_base = VGIC_ADDR_UNDEF;
dist->vgic_redist_base = VGIC_ADDR_UNDEF;
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 5d0f6ee..796964a 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -111,6 +111,14 @@ static void vgic_unqueue_lpi(struct kvm_vcpu *vcpu, int irq)
vcpu->kvm->arch.vgic.vm_ops.unqueue_lpi(vcpu, irq);
}
+static bool vgic_check_lpis(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->kvm->arch.vgic.vm_ops.check_lpis)
+ return vcpu->kvm->arch.vgic.vm_ops.check_lpis(vcpu);
+ else
+ return false;
+}
+
int kvm_vgic_map_resources(struct kvm *kvm)
{
return kvm->arch.vgic.vm_ops.map_resources(kvm, vgic);
@@ -1036,8 +1044,11 @@ static int compute_pending_for_cpu(struct kvm_vcpu *vcpu)
pending_private = find_first_bit(pend_percpu, VGIC_NR_PRIVATE_IRQS);
pending_shared = find_first_bit(pend_shared, nr_shared);
- return (pending_private < VGIC_NR_PRIVATE_IRQS ||
- pending_shared < vgic_nr_shared_irqs(dist));
+ if (pending_private < VGIC_NR_PRIVATE_IRQS ||
+ pending_shared < vgic_nr_shared_irqs(dist))
+ return true;
+
+ return vgic_check_lpis(vcpu);
}
/*
@@ -1148,6 +1159,10 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) {
struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
+ /* We don't care about LPIs here */
+ if (vlr.irq >= 8192)
+ continue;
+
if (!vgic_irq_is_enabled(vcpu, vlr.irq)) {
vgic_retire_lr(lr, vcpu);
if (vgic_irq_is_queued(vcpu, vlr.irq))