From: Andre Przywara <andre.przywara@arm.com>
To: Christoffer Dall <christoffer.dall@linaro.org>,
Marc Zyngier <marc.zyngier@arm.com>,
Eric Auger <eric.auger@linaro.org>
Cc: linux-arm-kernel@lists.infradead.org,
kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org
Subject: [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
Date: Fri, 25 Mar 2016 02:04:29 +0000 [thread overview]
Message-ID: <1458871508-17279-7-git-send-email-andre.przywara@arm.com> (raw)
In-Reply-To: <1458871508-17279-1-git-send-email-andre.przywara@arm.com>
From: Christoffer Dall <christoffer.dall@linaro.org>
Provide a vgic_queue_irq() function which decides whether a given
IRQ needs to be queued to a VCPU's ap_list.
This should be called whenever an IRQ became pending or got enabled,
either as a result of userspace injection, from in-kernel emulated
devices like the architected timer or from MMIO accesses to the
distributor emulation.
Also provides the necessary functions to allow userland to inject an
IRQ to a guest.
[Andre: refactor out vgic_queue_irq()]
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
include/kvm/vgic/vgic.h | 3 +
virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 185 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 659f8b1..f32b284 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -178,6 +178,9 @@ struct vgic_cpu {
struct list_head ap_list_head;
};
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+ bool level);
+
#define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel))
#define vgic_initialized(k) (false)
#define vgic_ready(k) ((k)->arch.vgic.ready)
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 8e34916..a95aabc 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -19,8 +19,25 @@
#include "vgic.h"
+#define CREATE_TRACE_POINTS
+#include "../trace.h"
+
struct vgic_global kvm_vgic_global_state;
+/*
+ * Locking order is always:
+ * vgic_cpu->ap_list_lock
+ * vgic_irq->irq_lock
+ *
+ * (that is, always take the ap_list_lock before the struct vgic_irq lock).
+ *
+ * When taking more than one ap_list_lock at the same time, always take the
+ * lowest numbered VCPU's ap_list_lock first, so:
+ * vcpuX->vcpu_id < vcpuY->vcpu_id:
+ * spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
+ * spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
+ */
+
struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
u32 intid)
{
@@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
WARN(1, "Looking up struct vgic_irq for reserved INTID");
return NULL;
}
+
+/**
+ * kvm_vgic_target_oracle - compute the target vcpu for an irq
+ *
+ * @irq: The irq to route. Must be already locked.
+ *
+ * Based on the current state of the interrupt (enabled, pending,
+ * active, vcpu and target_vcpu), compute the next vcpu this should be
+ * given to. Return NULL if this shouldn't be injected at all.
+ */
+static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
+{
+ /* If the interrupt is active, it must stay on the current vcpu */
+ if (irq->active)
+ return irq->vcpu;
+
+ /* If enabled and pending, it can migrate to a new one */
+ if (irq->enabled && irq->pending)
+ return irq->target_vcpu;
+
+ /* Otherwise, it is considered idle */
+ return NULL;
+}
+
+/*
+ * Only valid injection if changing level for level-triggered IRQs or for a
+ * rising edge.
+ */
+static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
+{
+ switch (irq->config) {
+ case VGIC_CONFIG_LEVEL:
+ return irq->line_level != level;
+ case VGIC_CONFIG_EDGE:
+ return level;
+ default:
+ BUG();
+ }
+}
+
+/*
+ * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
+ * Do the queuing if necessary, taking the right locks in the right order.
+ * Returns true when the IRQ was queued, false otherwise.
+ *
+ * Needs to be entered with the IRQ lock already held, but will return
+ * with all locks dropped.
+ */
+bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)
+{
+ struct kvm_vcpu *vcpu = vgic_target_oracle(irq);
+
+ if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
+ /*
+ * If this IRQ is already on a VCPU's ap_list, then it
+ * cannot be moved or modified and there is no more work for
+ * us to do.
+ *
+ * Otherwise, if the irq is not pending and enabled, it does
+ * not need to be inserted into an ap_list and there is also
+ * no more work for us to do.
+ */
+ spin_unlock(&irq->irq_lock);
+ return false;
+ }
+
+ /*
+ * We must unlock the irq lock to take the ap_list_lock where
+ * we are going to insert this new pending interrupt.
+ */
+ spin_unlock(&irq->irq_lock);
+
+ /* someone can do stuff here, which we re-check below */
+retry:
+ spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+ spin_lock(&irq->irq_lock);
+
+ /*
+ * Did something change behind our backs?
+ *
+ * There are two cases:
+ * 1) The irq became pending or active behind our backs and/or
+ * the irq->vcpu field was set correspondingly when putting
+ * the irq on an ap_list. Then drop the locks and return.
+ * 2) Someone changed the affinity on this irq behind our
+ * backs and we are now holding the wrong ap_list_lock.
+ * Then drop the locks and try the new VCPU.
+ */
+ if (irq->vcpu || !(irq->pending && irq->enabled)) {
+ spin_unlock(&irq->irq_lock);
+ spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+ return false;
+ }
+
+ if (irq->target_vcpu != vcpu) {
+ spin_unlock(&irq->irq_lock);
+ spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+ vcpu = irq->target_vcpu;
+ goto retry;
+ }
+
+ list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
+ irq->vcpu = vcpu;
+
+ spin_unlock(&irq->irq_lock);
+ spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+ kvm_vcpu_kick(vcpu);
+
+ return true;
+}
+
+static void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
+ u32 intid, bool level)
+{
+ struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
+
+ trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
+
+ BUG_ON(in_interrupt());
+
+ spin_lock(&irq->irq_lock);
+
+ if (!vgic_validate_injection(irq, level)) {
+ /* Nothing to see here, move along... */
+ spin_unlock(&irq->irq_lock);
+ return;
+ }
+
+ if (irq->config == VGIC_CONFIG_LEVEL) {
+ irq->line_level = level;
+ irq->pending = level || irq->soft_pending;
+ } else {
+ irq->pending = true;
+ }
+
+ vgic_queue_irq(kvm, irq);
+}
+
+/**
+ * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
+ * @kvm: The VM structure pointer
+ * @cpuid: The CPU for PPIs
+ * @intid: The INTID to inject a new state to.
+ * must not be mapped to a HW interrupt.
+ * @level: Edge-triggered: true: to trigger the interrupt
+ * false: to ignore the call
+ * Level-sensitive true: raise the input signal
+ * false: lower the input signal
+ *
+ * The GIC is not concerned with devices being active-LOW or active-HIGH for
+ * level-sensitive interrupts. You can think of the level parameter as 1
+ * being HIGH and 0 being LOW and all devices being active-HIGH.
+ */
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+ bool level)
+{
+ struct kvm_vcpu *vcpu;
+
+ vcpu = kvm_get_vcpu(kvm, cpuid);
+ vgic_update_irq_pending(kvm, vcpu, intid, level);
+ return 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 61b8d22..e9f4aa6 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -18,5 +18,6 @@
struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
u32 intid);
+bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
#endif
--
2.7.3
next prev parent reply other threads:[~2016-03-25 2:04 UTC|newest]
Thread overview: 138+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-25 2:04 [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 01/45] KVM: arm/arm64: add missing MMIO data write-back Andre Przywara
2016-03-29 12:33 ` Christoffer Dall
2016-04-05 12:12 ` Andre Przywara
2016-04-05 12:58 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 02/45] KVM: arm/arm64: pmu: abstract access to number of SPIs Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 03/45] KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface Andre Przywara
2016-03-29 13:01 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions Andre Przywara
2016-03-29 13:09 ` Christoffer Dall
2016-04-05 13:34 ` Andre Przywara
2016-04-05 20:10 ` Christoffer Dall
2016-04-06 13:57 ` Christoffer Dall
2016-04-06 14:09 ` Andre Przywara
2016-04-06 14:46 ` Christoffer Dall
2016-04-06 14:53 ` Andre Przywara
2016-04-06 14:57 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance Andre Przywara
2016-03-25 2:04 ` Andre Przywara [this message]
2016-03-29 21:16 ` [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection Christoffer Dall
2016-04-05 17:28 ` Andre Przywara
2016-04-06 14:23 ` Christoffer Dall
2016-04-14 10:53 ` Andre Przywara
2016-04-14 12:15 ` Christoffer Dall
2016-04-14 13:45 ` Andre Przywara
2016-04-14 14:05 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 07/45] KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity Andre Przywara
2016-03-30 9:29 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 08/45] KVM: arm/arm64: vgic-new: Add IRQ sorting Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush Andre Przywara
2016-03-30 13:53 ` Christoffer Dall
2016-04-05 17:57 ` Andre Przywara
2016-04-06 14:34 ` Christoffer Dall
2016-03-31 9:47 ` Christoffer Dall
2016-04-11 11:40 ` Andre Przywara
2016-04-12 12:25 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend Andre Przywara
2016-03-30 20:40 ` Christoffer Dall
2016-04-12 13:59 ` Andre Przywara
2016-04-12 15:02 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 11/45] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq Andre Przywara
2016-03-31 8:54 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework Andre Przywara
2016-03-31 9:08 ` Christoffer Dall
2016-03-31 9:09 ` Christoffer Dall
2016-03-31 12:25 ` Paolo Bonzini
2016-03-31 14:31 ` Christoffer Dall
2016-04-01 12:11 ` André Przywara
2016-04-01 12:17 ` Christoffer Dall
2016-04-11 10:53 ` Andre Przywara
2016-04-12 12:50 ` Christoffer Dall
2016-04-12 15:56 ` Marc Zyngier
2016-04-12 17:26 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface Andre Przywara
2016-03-31 9:24 ` Christoffer Dall
2016-04-11 11:09 ` Andre Przywara
2016-04-12 12:52 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers Andre Przywara
2016-03-31 9:27 ` Christoffer Dall
2016-04-11 11:23 ` Andre Przywara
2016-04-12 12:55 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 15/45] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers Andre Przywara
2016-03-31 9:33 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING " Andre Przywara
2016-03-31 9:35 ` Christoffer Dall
2016-04-11 11:31 ` Andre Przywara
2016-04-12 13:10 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 17/45] KVM: arm/arm64: vgic-new: Add PRIORITY " Andre Przywara
2016-03-31 9:50 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 18/45] KVM: arm/arm64: vgic-new: Add ACTIVE " Andre Przywara
2016-03-31 9:58 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 19/45] KVM: arm/arm64: vgic-new: Add CONFIG " Andre Przywara
2016-03-31 10:07 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET " Andre Przywara
2016-03-31 11:31 ` Christoffer Dall
2016-04-11 12:10 ` Andre Przywara
2016-04-12 13:18 ` Christoffer Dall
2016-04-12 15:18 ` Andre Przywara
2016-04-12 15:26 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 21/45] KVM: arm/arm64: vgic-new: Add SGIR register handler Andre Przywara
2016-03-31 11:35 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 22/45] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers Andre Przywara
2016-03-31 11:37 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 emulation framework Andre Przywara
2016-03-31 11:48 ` Christoffer Dall
2016-04-11 12:44 ` Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers Andre Przywara
2016-03-31 11:53 ` Christoffer Dall
2016-04-11 13:00 ` Andre Przywara
2016-04-12 13:20 ` Christoffer Dall
2016-03-25 2:04 ` [RFC PATCH 25/45] KVM: arm/arm64: vgic-new: Add GICv3 redistributor TYPER handler Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 27/45] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler Andre Przywara
2016-03-31 12:07 ` Christoffer Dall
2016-04-11 13:11 ` Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 29/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 30/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 31/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 32/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 33/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 34/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 35/45] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers Andre Przywara
2016-03-25 2:04 ` [RFC PATCH 36/45] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors Andre Przywara
2016-03-25 2:05 ` [RFC PATCH 37/45] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access Andre Przywara
2016-03-25 2:05 ` [RFC PATCH 38/45] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init Andre Przywara
2016-03-25 2:05 ` [RFC PATCH 39/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create Andre Przywara
2016-03-25 2:05 ` [RFC PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init Andre Przywara
2016-03-31 17:59 ` Christoffer Dall
2016-04-01 8:20 ` Eric Auger
2016-04-01 9:00 ` Christoffer Dall
2016-03-25 2:05 ` [RFC PATCH 41/45] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources Andre Przywara
2016-03-25 2:05 ` [RFC PATCH 42/45] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable Andre Przywara
2016-03-25 2:05 ` [RFC PATCH 43/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling Andre Przywara
2016-03-31 18:15 ` Christoffer Dall
2016-04-01 8:44 ` Eric Auger
2016-03-25 2:05 ` [RFC PATCH 44/45] KVM: arm/arm64: vgic-new: Add dummy MSI implementation Andre Przywara
2016-03-31 18:16 ` Christoffer Dall
2016-04-07 14:35 ` Eric Auger
2016-03-25 2:05 ` [RFC PATCH 45/45] KVM: arm/arm64: vgic-new: enable build Andre Przywara
2016-03-31 18:18 ` Christoffer Dall
2016-04-11 14:45 ` Andre Przywara
2016-04-12 13:21 ` Christoffer Dall
2016-03-25 15:58 ` [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Diana Madalina Craciun
2016-03-26 2:11 ` André Przywara
2016-03-29 13:12 ` Vladimir Murzin
2016-03-30 11:42 ` Vladimir Murzin
2016-03-30 11:52 ` Vladimir Murzin
2016-03-30 13:56 ` Christoffer Dall
2016-03-30 14:13 ` Vladimir Murzin
2016-03-30 19:53 ` Christoffer Dall
2016-03-30 12:07 ` Marc Zyngier
2016-03-30 19:55 ` Christoffer Dall
2016-03-31 9:06 ` Marc Zyngier
2016-03-31 18:28 ` Christoffer Dall
2016-03-31 18:30 ` Christoffer Dall
2016-04-13 16:07 ` André Przywara
2016-04-13 17:24 ` Christoffer Dall
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1458871508-17279-7-git-send-email-andre.przywara@arm.com \
--to=andre.przywara@arm.com \
--cc=christoffer.dall@linaro.org \
--cc=eric.auger@linaro.org \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=marc.zyngier@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox