linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation
@ 2015-07-10 14:21 Andre Przywara
  2015-07-10 14:21 ` [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor Andre Przywara
                   ` (16 more replies)
  0 siblings, 17 replies; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

this respin tries to address all comments I got so far from the list.
Thanks to Eric, Pavel and Christoffer for the review!
The major change in this series is the reworked locking. The current
implementation is now much more fine grained and avoids any calls to
functions that could possibly sleep when the ITS spinlock is held.
For many command handlers this change was straight forward, for some
memory is pre-allocated to avoid kmalloc calls. The function actually
triggering the command processing required some more trickery
(see patch 09/15).
Patch 01, 03, 06, 07, 10 were mostly unchanged, see the Changelog
below for a list of changes in the rest. On [1] there is a branch
called its-emul/v1-updated which is v1 plus the fixes rebased on top
of 4.2-rc1 and has all the changes from v2 in one single commit on
top of it.

Please have a look and feel free to ask questions or give comments.
Also holler if I should have missed to address a previous comment.
For this drop I haven't considered Eric's IRQ routing series too
much, but we should definitely coordinate those two series from this
point on.

Cheers,
Andre.

Changelog v1..v2
- fix issues when using non-ITS GICv3 emulation
- streamline frame address initialization (new patch 05/15)
- preallocate buffer memory for reading from guest's memory
- move locking into the actual command handlers
-   preallocate memory for new structures if needed
- use non-atomic __set_bit() and __clear_bit() when under the lock
- add INT command handler to allow LPI injection from the guest
- rewrite CWRITER handler to align with new locking scheme
- remove unneeded CONFIG_HAVE_KVM_MSI #ifdefs
- check memory table size against our LPI limit (65536 interrupts)
- observe initial gap of 1024 interrupts in pending table
- use term "configuration table" to be in line with the spec
- clarify and extend documentation on API extensions
- introduce new KVM_CAP_MSI_DEVID capability to advertise device ID requirement
- update, fix and add many comments
- minor style changes as requested by reviewers

---------------

The GICv3 ITS (Interrupt Translation Service) is a part of the
ARM GICv3 interrupt controller [3] used for implementing MSIs.
It specifies a new kind of interrupts (LPIs), which are mapped to
establish a connection between a device, its MSI payload value and
the target processor the IRQ is eventually delivered to.
In order to allow using MSIs in an ARM64 KVM guest, we emulate this
ITS widget in the kernel.
The ITS works by reading commands written by software (from the guest
in our case) into a (guest allocated) memory region and establishing
the mapping between a device, the MSI payload and the target CPU.
We parse these commands and update our internal data structures to
reflect those changes. On an MSI injection we iterate those
structures to learn the LPI number we have to inject.
For the time being we use simple lists to hold the data, this is
good enough for the small number of entries each of the components
currently have. Should this become a performance bottleneck in the
future, those can be extended to arrays or trees if needed.

Most of the code lives in a separate source file (its-emul.c), though
there are some changes necessary both in vgic.c and vgic-v3-emul.c.

Patch 01/15 gets rid of the internal tracking of the used LR for
an injected IRQ, see the commit message for more details.
Patch 02/13 extends the KVM MSI ioctl to hold a device ID.
Patch 03-05 make small changes to the existing VGIC code which make
adaptions to the ITS later easier.
The rest of the patches implement the ITS functionality step by step.
For more details see the respective commit messages.

For the time being this series gives us the ability to use emulated
PCI devices that can use MSIs in the guest. Those have to be
triggered by letting the userland device emulation simulate the MSI
write with the KVM_SIGNAL_MSI ioctl. This will be translated into
the proper LPI by the ITS emulation and injected into the guest in
the usual way (just with a higher IRQ number).

This series is based on 4.2-rc1 and can be found at the its-emul/v2
branch of this repository [1].
For this to be used you need a GICv3 host machine (a fast model would
do), though it does not rely on any host ITS bits (neither in hardware
or software).

To test this you can use the kvmtool patches available in the "its"
branch here [2].
Start a guest with: "$ lkvm run --irqchip=gicv3-its --force-pci"
and see the ITS being used for instance by the virtio devices.

[1]: git://linux-arm.org/linux-ap.git
     http://www.linux-arm.org/git?p=linux-ap.git;a=log;h=refs/heads/its-emul/v2
[2]: git://linux-arm.org/kvmtool.git
     http://www.linux-arm.org/git?p=kvmtool.git;a=log;h=refs/heads/its
[3]: http://arminfo.emea.arm.com/help/topic/com.arm.doc.ihi0069a/IHI0069A_gic_architecture_specification.pdf

Andre Przywara (15):
  KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  KVM: extend struct kvm_msi to hold a 32-bit device ID
  KVM: arm/arm64: add emulation model specific destroy function
  KVM: arm/arm64: extend arch CAP checks to allow per-VM capabilities
  KVM: arm/arm64: make GIC frame address initialization model specific
  KVM: arm64: Introduce new MMIO region for the ITS base address
  KVM: arm64: handle ITS related GICv3 redistributor registers
  KVM: arm64: introduce ITS emulation file with stub functions
  KVM: arm64: implement basic ITS register handlers
  KVM: arm64: add data structures to model ITS interrupt translation
  KVM: arm64: handle pending bit for LPIs in ITS emulation
  KVM: arm64: sync LPI configuration and pending tables
  KVM: arm64: implement ITS command queue command handlers
  KVM: arm64: implement MSI injection in ITS emulation
  KVM: arm64: enable ITS emulation as a virtual MSI controller

 Documentation/virtual/kvm/api.txt              |   14 +-
 Documentation/virtual/kvm/devices/arm-vgic.txt |    9 +
 arch/arm/include/asm/kvm_host.h                |    2 +-
 arch/arm/kvm/arm.c                             |    2 +-
 arch/arm64/include/asm/kvm_host.h              |    2 +-
 arch/arm64/include/uapi/asm/kvm.h              |    2 +
 arch/arm64/kvm/Kconfig                         |    1 +
 arch/arm64/kvm/Makefile                        |    1 +
 arch/arm64/kvm/reset.c                         |    8 +-
 include/kvm/arm_vgic.h                         |   41 +-
 include/linux/irqchip/arm-gic-v3.h             |   14 +-
 include/uapi/linux/kvm.h                       |    5 +-
 virt/kvm/arm/its-emul.c                        | 1141 ++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h                        |   55 ++
 virt/kvm/arm/vgic-v2-emul.c                    |    3 +
 virt/kvm/arm/vgic-v2.c                         |    1 +
 virt/kvm/arm/vgic-v3-emul.c                    |  105 ++-
 virt/kvm/arm/vgic-v3.c                         |    1 +
 virt/kvm/arm/vgic.c                            |  284 ++++--
 virt/kvm/arm/vgic.h                            |    5 +
 20 files changed, 1575 insertions(+), 121 deletions(-)
 create mode 100644 virt/kvm/arm/its-emul.c
 create mode 100644 virt/kvm/arm/its-emul.h

-- 
2.3.5

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-08-12  9:01   ` Eric Auger
  2015-10-02  9:55   ` Pavel Fedin
  2015-07-10 14:21 ` [PATCH v2 02/15] KVM: extend struct kvm_msi to hold a 32-bit device ID Andre Przywara
                   ` (15 subsequent siblings)
  16 siblings, 2 replies; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

Currently we track which IRQ has been mapped to which VGIC list
register and also have to synchronize both. We used to do this
to hold some extra state (for instance the active bit).
It turns out that this extra state in the LRs is no longer needed and
this extra tracking causes some pain later.
Remove the tracking feature (lr_map and lr_used) and get rid of
quite some code on the way.
On a guest exit we pick up all still pending IRQs from the LRs and put
them back in the distributor. We don't care about active-only IRQs,
so we keep them in the LRs. They will be retired either by our
vgic_process_maintenance() routine or by the GIC hardware in case of
edge triggered interrupts.
In places where we scan LRs we now use our shadow copy of the ELRSR
register directly.
This code change means we lose the "piggy-back" optimization, which
would re-use an active-only LR to inject the pending state on top of
it. Tracing with various workloads shows that this actually occurred
very rarely, the ballpark figure is about once every 10,000 exits
in a disk I/O heavy workload. Also the list registers don't seem to
as scarce as assumed, with all 4 LRs on the popular implementations
used less than once every 100,000 exits.

This has been briefly tested on Midway, Juno and the model (the latter
both with GICv2 and GICv3 guests).

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h |   6 ---
 virt/kvm/arm/vgic-v2.c |   1 +
 virt/kvm/arm/vgic-v3.c |   1 +
 virt/kvm/arm/vgic.c    | 143 ++++++++++++++++++++++---------------------------
 4 files changed, 66 insertions(+), 85 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 133ea00..2ccfa9a 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -279,9 +279,6 @@ struct vgic_v3_cpu_if {
 };
 
 struct vgic_cpu {
-	/* per IRQ to LR mapping */
-	u8		*vgic_irq_lr_map;
-
 	/* Pending/active/both interrupts on this VCPU */
 	DECLARE_BITMAP(	pending_percpu, VGIC_NR_PRIVATE_IRQS);
 	DECLARE_BITMAP(	active_percpu, VGIC_NR_PRIVATE_IRQS);
@@ -292,9 +289,6 @@ struct vgic_cpu {
 	unsigned long   *active_shared;
 	unsigned long   *pend_act_shared;
 
-	/* Bitmap of used/free list registers */
-	DECLARE_BITMAP(	lr_used, VGIC_V2_MAX_LRS);
-
 	/* Number of list registers on this CPU */
 	int		nr_lr;
 
diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c
index f9b9c7c..f723710 100644
--- a/virt/kvm/arm/vgic-v2.c
+++ b/virt/kvm/arm/vgic-v2.c
@@ -144,6 +144,7 @@ static void vgic_v2_enable(struct kvm_vcpu *vcpu)
 	 * anyway.
 	 */
 	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = 0;
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr = ~0;
 
 	/* Get the show on the road... */
 	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
index dff0602..21e5d28 100644
--- a/virt/kvm/arm/vgic-v3.c
+++ b/virt/kvm/arm/vgic-v3.c
@@ -178,6 +178,7 @@ static void vgic_v3_enable(struct kvm_vcpu *vcpu)
 	 * anyway.
 	 */
 	vgic_v3->vgic_vmcr = 0;
+	vgic_v3->vgic_elrsr = ~0;
 
 	/*
 	 * If we are emulating a GICv3, we do it in an non-GICv2-compatible
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index bc40137..394622c 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -79,7 +79,6 @@
 #include "vgic.h"
 
 static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu);
-static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu);
 static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr);
 static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr, struct vgic_lr lr_desc);
 
@@ -647,6 +646,17 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
 	return false;
 }
 
+static void vgic_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
+			       struct vgic_lr vlr)
+{
+	vgic_ops->sync_lr_elrsr(vcpu, lr, vlr);
+}
+
+static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
+{
+	return vgic_ops->get_elrsr(vcpu);
+}
+
 /**
  * vgic_unqueue_irqs - move pending/active IRQs from LRs to the distributor
  * @vgic_cpu: Pointer to the vgic_cpu struct holding the LRs
@@ -658,9 +668,11 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
 void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	u64 elrsr = vgic_get_elrsr(vcpu);
+	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
 	int i;
 
-	for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) {
+	for_each_clear_bit(i, elrsr_ptr, vgic_cpu->nr_lr) {
 		struct vgic_lr lr = vgic_get_lr(vcpu, i);
 
 		/*
@@ -703,7 +715,7 @@ void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
 		 * Mark the LR as free for other use.
 		 */
 		BUG_ON(lr.state & LR_STATE_MASK);
-		vgic_retire_lr(i, lr.irq, vcpu);
+		vgic_sync_lr_elrsr(vcpu, i, lr);
 		vgic_irq_clear_queued(vcpu, lr.irq);
 
 		/* Finally update the VGIC state. */
@@ -1011,17 +1023,6 @@ static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr,
 	vgic_ops->set_lr(vcpu, lr, vlr);
 }
 
-static void vgic_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
-			       struct vgic_lr vlr)
-{
-	vgic_ops->sync_lr_elrsr(vcpu, lr, vlr);
-}
-
-static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
-{
-	return vgic_ops->get_elrsr(vcpu);
-}
-
 static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
 {
 	return vgic_ops->get_eisr(vcpu);
@@ -1062,18 +1063,6 @@ static inline void vgic_enable(struct kvm_vcpu *vcpu)
 	vgic_ops->enable(vcpu);
 }
 
-static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
-{
-	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
-	struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr);
-
-	vlr.state = 0;
-	vgic_set_lr(vcpu, lr_nr, vlr);
-	clear_bit(lr_nr, vgic_cpu->lr_used);
-	vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
-	vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
-}
-
 /*
  * An interrupt may have been disabled after being made pending on the
  * CPU interface (the classic case is a timer running while we're
@@ -1085,23 +1074,32 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
  */
 static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
 {
-	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	u64 elrsr = vgic_get_elrsr(vcpu);
+	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
 	int lr;
+	struct vgic_lr vlr;
 
-	for_each_set_bit(lr, vgic_cpu->lr_used, vgic->nr_lr) {
-		struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
+	for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) {
+		vlr = vgic_get_lr(vcpu, lr);
 
 		if (!vgic_irq_is_enabled(vcpu, vlr.irq)) {
-			vgic_retire_lr(lr, vlr.irq, vcpu);
-			if (vgic_irq_is_queued(vcpu, vlr.irq))
-				vgic_irq_clear_queued(vcpu, vlr.irq);
+			vlr.state = 0;
+			vgic_set_lr(vcpu, lr, vlr);
+			vgic_sync_lr_elrsr(vcpu, lr, vlr);
+			vgic_irq_clear_queued(vcpu, vlr.irq);
 		}
 	}
 }
 
 static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
-				 int lr_nr, struct vgic_lr vlr)
+				 int lr_nr, int sgi_source_id)
 {
+	struct vgic_lr vlr;
+
+	vlr.state = 0;
+	vlr.irq = irq;
+	vlr.source = sgi_source_id;
+
 	if (vgic_irq_is_active(vcpu, irq)) {
 		vlr.state |= LR_STATE_ACTIVE;
 		kvm_debug("Set active, clear distributor: 0x%x\n", vlr.state);
@@ -1126,9 +1124,9 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
  */
 bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
 {
-	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-	struct vgic_lr vlr;
+	u64 elrsr = vgic_get_elrsr(vcpu);
+	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
 	int lr;
 
 	/* Sanitize the input... */
@@ -1138,42 +1136,20 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
 
 	kvm_debug("Queue IRQ%d\n", irq);
 
-	lr = vgic_cpu->vgic_irq_lr_map[irq];
-
-	/* Do we have an active interrupt for the same CPUID? */
-	if (lr != LR_EMPTY) {
-		vlr = vgic_get_lr(vcpu, lr);
-		if (vlr.source == sgi_source_id) {
-			kvm_debug("LR%d piggyback for IRQ%d\n", lr, vlr.irq);
-			BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
-			vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
-			return true;
-		}
-	}
+	lr = find_first_bit(elrsr_ptr, vgic->nr_lr);
 
-	/* Try to use another LR for this interrupt */
-	lr = find_first_zero_bit((unsigned long *)vgic_cpu->lr_used,
-			       vgic->nr_lr);
 	if (lr >= vgic->nr_lr)
 		return false;
 
 	kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id);
-	vgic_cpu->vgic_irq_lr_map[irq] = lr;
-	set_bit(lr, vgic_cpu->lr_used);
 
-	vlr.irq = irq;
-	vlr.source = sgi_source_id;
-	vlr.state = 0;
-	vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
+	vgic_queue_irq_to_lr(vcpu, irq, lr, sgi_source_id);
 
 	return true;
 }
 
 static bool vgic_queue_hwirq(struct kvm_vcpu *vcpu, int irq)
 {
-	if (!vgic_can_sample_irq(vcpu, irq))
-		return true; /* level interrupt, already queued */
-
 	if (vgic_queue_irq(vcpu, 0, irq)) {
 		if (vgic_irq_is_edge(vcpu, irq)) {
 			vgic_dist_irq_clear_pending(vcpu, irq);
@@ -1346,29 +1322,44 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	u64 elrsr;
 	unsigned long *elrsr_ptr;
-	int lr, pending;
-	bool level_pending;
+	struct vgic_lr vlr;
+	int lr_nr;
+	bool pending;
+
+	pending = vgic_process_maintenance(vcpu);
 
-	level_pending = vgic_process_maintenance(vcpu);
 	elrsr = vgic_get_elrsr(vcpu);
 	elrsr_ptr = u64_to_bitmask(&elrsr);
 
-	/* Clear mappings for empty LRs */
-	for_each_set_bit(lr, elrsr_ptr, vgic->nr_lr) {
-		struct vgic_lr vlr;
+	for_each_clear_bit(lr_nr, elrsr_ptr, vgic_cpu->nr_lr) {
+		vlr = vgic_get_lr(vcpu, lr_nr);
+
+		BUG_ON(!(vlr.state & LR_STATE_MASK));
+		pending = true;
 
-		if (!test_and_clear_bit(lr, vgic_cpu->lr_used))
+		/* Reestablish SGI source for pending and active SGIs */
+		if (vlr.irq < VGIC_NR_SGIS)
+			add_sgi_source(vcpu, vlr.irq, vlr.source);
+
+		/*
+		 * If the LR holds a pure active (10) interrupt then keep it
+		 * in the LR without mirroring this status in the emulation.
+		 */
+		if (vlr.state == LR_STATE_ACTIVE)
 			continue;
 
-		vlr = vgic_get_lr(vcpu, lr);
+		if (vlr.state & LR_STATE_PENDING)
+			vgic_dist_irq_set_pending(vcpu, vlr.irq);
 
-		BUG_ON(vlr.irq >= dist->nr_irqs);
-		vgic_cpu->vgic_irq_lr_map[vlr.irq] = LR_EMPTY;
+		/* Mark this LR as empty now. */
+		vlr.state = 0;
+		vgic_set_lr(vcpu, lr_nr, vlr);
+		vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
 	}
+	vgic_update_state(vcpu->kvm);
 
-	/* Check if we still have something up our sleeve... */
-	pending = find_first_zero_bit(elrsr_ptr, vgic->nr_lr);
-	if (level_pending || pending < vgic->nr_lr)
+	/* vgic_update_state would not cover only-active IRQs */
+	if (pending)
 		set_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu);
 }
 
@@ -1590,11 +1581,9 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
 	kfree(vgic_cpu->pending_shared);
 	kfree(vgic_cpu->active_shared);
 	kfree(vgic_cpu->pend_act_shared);
-	kfree(vgic_cpu->vgic_irq_lr_map);
 	vgic_cpu->pending_shared = NULL;
 	vgic_cpu->active_shared = NULL;
 	vgic_cpu->pend_act_shared = NULL;
-	vgic_cpu->vgic_irq_lr_map = NULL;
 }
 
 static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
@@ -1605,18 +1594,14 @@ static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
 	vgic_cpu->pending_shared = kzalloc(sz, GFP_KERNEL);
 	vgic_cpu->active_shared = kzalloc(sz, GFP_KERNEL);
 	vgic_cpu->pend_act_shared = kzalloc(sz, GFP_KERNEL);
-	vgic_cpu->vgic_irq_lr_map = kmalloc(nr_irqs, GFP_KERNEL);
 
 	if (!vgic_cpu->pending_shared
 		|| !vgic_cpu->active_shared
-		|| !vgic_cpu->pend_act_shared
-		|| !vgic_cpu->vgic_irq_lr_map) {
+		|| !vgic_cpu->pend_act_shared) {
 		kvm_vgic_vcpu_destroy(vcpu);
 		return -ENOMEM;
 	}
 
-	memset(vgic_cpu->vgic_irq_lr_map, LR_EMPTY, nr_irqs);
-
 	/*
 	 * Store the number of LRs per vcpu, so we don't have to go
 	 * all the way to the distributor structure to find out. Only
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 02/15] KVM: extend struct kvm_msi to hold a 32-bit device ID
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
  2015-07-10 14:21 ` [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-07-10 14:21 ` [PATCH v2 03/15] KVM: arm/arm64: add emulation model specific destroy function Andre Przywara
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

The ARM GICv3 ITS MSI controller requires a device ID to be able to
assign the proper interrupt vector. On real hardware, this ID is
sampled from the bus. To be able to emulate an ITS controller, extend
the KVM MSI interface to let userspace provide such a device ID. For
PCI devices, the device ID is simply the 16-bit bus-device-function
triplet, which should be easily available to the userland tool.

Also there is a new KVM capability which advertises whether the
current VM requires a device ID to be set along with the MSI data.
This flag is still reported as not available everywhere, later we will
enable it when ITS emulation is used.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
 Documentation/virtual/kvm/api.txt | 12 ++++++++++--
 include/uapi/linux/kvm.h          |  5 ++++-
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index a7926a9..cb04095 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2147,10 +2147,18 @@ struct kvm_msi {
 	__u32 address_hi;
 	__u32 data;
 	__u32 flags;
-	__u8  pad[16];
+	__u32 devid;
+	__u8  pad[12];
 };
 
-No flags are defined so far. The corresponding field must be 0.
+flags: KVM_MSI_VALID_DEVID: devid contains a valid value
+devid: If KVM_MSI_VALID_DEVID is set, contains a unique device identifier
+       for the device that wrote the MSI message.
+       For PCI, this is usually a BFD identifier in the lower 16 bits.
+
+The per-VM KVM_CAP_MSI_DEVID capability advertises the need to provide
+the device ID. If this capability is not set, userland cannot rely on
+the kernel to allow the KVM_MSI_VALID_DEVID flag being set.
 
 
 4.71 KVM_CREATE_PIT2
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 716ad4a..1c48def 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -817,6 +817,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_DISABLE_QUIRKS 116
 #define KVM_CAP_X86_SMM 117
 #define KVM_CAP_MULTI_ADDRESS_SPACE 118
+#define KVM_CAP_MSI_DEVID 119
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -968,12 +969,14 @@ struct kvm_one_reg {
 	__u64 addr;
 };
 
+#define KVM_MSI_VALID_DEVID	(1U << 0)
 struct kvm_msi {
 	__u32 address_lo;
 	__u32 address_hi;
 	__u32 data;
 	__u32 flags;
-	__u8  pad[16];
+	__u32 devid;
+	__u8  pad[12];
 };
 
 struct kvm_arm_device_addr {
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 03/15] KVM: arm/arm64: add emulation model specific destroy function
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
  2015-07-10 14:21 ` [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor Andre Przywara
  2015-07-10 14:21 ` [PATCH v2 02/15] KVM: extend struct kvm_msi to hold a 32-bit device ID Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-07-10 14:21 ` [PATCH v2 04/15] KVM: arm/arm64: extend arch CAP checks to allow per-VM capabilities Andre Przywara
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

Currently we destroy the VGIC emulation in one function that cares for
all emulated models. To be on par with init_model (which is model
specific), lets introduce a per-emulation-model destroy method, too.
Use it for a tiny GICv3 specific code already, later it will be handy
for the ITS emulation.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
 include/kvm/arm_vgic.h      |  1 +
 virt/kvm/arm/vgic-v3-emul.c |  9 +++++++++
 virt/kvm/arm/vgic.c         | 11 ++++++++++-
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 2ccfa9a..b18e2c5 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -144,6 +144,7 @@ struct vgic_vm_ops {
 	bool	(*queue_sgi)(struct kvm_vcpu *, int irq);
 	void	(*add_sgi_source)(struct kvm_vcpu *, int irq, int source);
 	int	(*init_model)(struct kvm *);
+	void	(*destroy_model)(struct kvm *);
 	int	(*map_resources)(struct kvm *, const struct vgic_params *);
 };
 
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index e661e7f..d2eeb20 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -862,6 +862,14 @@ static int vgic_v3_init_model(struct kvm *kvm)
 	return 0;
 }
 
+static void vgic_v3_destroy_model(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	kfree(dist->irq_spi_mpidr);
+	dist->irq_spi_mpidr = NULL;
+}
+
 /* GICv3 does not keep track of SGI sources anymore. */
 static void vgic_v3_add_sgi_source(struct kvm_vcpu *vcpu, int irq, int source)
 {
@@ -874,6 +882,7 @@ void vgic_v3_init_emulation(struct kvm *kvm)
 	dist->vm_ops.queue_sgi = vgic_v3_queue_sgi;
 	dist->vm_ops.add_sgi_source = vgic_v3_add_sgi_source;
 	dist->vm_ops.init_model = vgic_v3_init_model;
+	dist->vm_ops.destroy_model = vgic_v3_destroy_model;
 	dist->vm_ops.map_resources = vgic_v3_map_resources;
 
 	kvm->arch.max_vcpus = KVM_MAX_VCPUS;
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 394622c..cc8f5ed 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -100,6 +100,14 @@ int kvm_vgic_map_resources(struct kvm *kvm)
 	return kvm->arch.vgic.vm_ops.map_resources(kvm, vgic);
 }
 
+static void vgic_destroy_model(struct kvm *kvm)
+{
+	struct vgic_vm_ops *vm_ops = &kvm->arch.vgic.vm_ops;
+
+	if (vm_ops->destroy_model)
+		vm_ops->destroy_model(kvm);
+}
+
 /*
  * struct vgic_bitmap contains a bitmap made of unsigned longs, but
  * extracts u32s out of them.
@@ -1629,6 +1637,8 @@ void kvm_vgic_destroy(struct kvm *kvm)
 	struct kvm_vcpu *vcpu;
 	int i;
 
+	vgic_destroy_model(kvm);
+
 	kvm_for_each_vcpu(i, vcpu, kvm)
 		kvm_vgic_vcpu_destroy(vcpu);
 
@@ -1645,7 +1655,6 @@ void kvm_vgic_destroy(struct kvm *kvm)
 	}
 	kfree(dist->irq_sgi_sources);
 	kfree(dist->irq_spi_cpu);
-	kfree(dist->irq_spi_mpidr);
 	kfree(dist->irq_spi_target);
 	kfree(dist->irq_pending_on_cpu);
 	kfree(dist->irq_active_on_cpu);
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 04/15] KVM: arm/arm64: extend arch CAP checks to allow per-VM capabilities
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (2 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 03/15] KVM: arm/arm64: add emulation model specific destroy function Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-08-12 12:26   ` Eric Auger
  2015-07-10 14:21 ` [PATCH v2 05/15] KVM: arm/arm64: make GIC frame address initialization model specific Andre Przywara
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

KVM capabilities can be a per-VM property, though ARM/ARM64 currently
does not pass on the VM pointer to the architecture specific
capability handlers.
Add a "struct kvm*" parameter to those function to later allow proper
per-VM capability reporting.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/include/asm/kvm_host.h   | 2 +-
 arch/arm/kvm/arm.c                | 2 +-
 arch/arm64/include/asm/kvm_host.h | 2 +-
 arch/arm64/kvm/reset.c            | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index e896d2c..56cac05 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -213,7 +213,7 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
 	kvm_call_hyp((void*)hyp_stack_ptr, vector_ptr, pgd_ptr);
 }
 
-static inline int kvm_arch_dev_ioctl_check_extension(long ext)
+static inline int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
 {
 	return 0;
 }
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index bc738d2..7c65353 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -196,7 +196,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 		r = KVM_MAX_VCPUS;
 		break;
 	default:
-		r = kvm_arch_dev_ioctl_check_extension(ext);
+		r = kvm_arch_dev_ioctl_check_extension(kvm, ext);
 		break;
 	}
 	return r;
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 2709db2..8d78a72 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -47,7 +47,7 @@
 
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
-int kvm_arch_dev_ioctl_check_extension(long ext);
+int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext);
 
 struct kvm_arch {
 	/* The VMID generation used for the virt. memory system */
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 0b43265..866502b 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -56,7 +56,7 @@ static bool cpu_has_32bit_el1(void)
 	return !!(pfr0 & 0x20);
 }
 
-int kvm_arch_dev_ioctl_check_extension(long ext)
+int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
 {
 	int r;
 
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 05/15] KVM: arm/arm64: make GIC frame address initialization model specific
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (3 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 04/15] KVM: arm/arm64: extend arch CAP checks to allow per-VM capabilities Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-08-12 13:02   ` Eric Auger
  2015-07-10 14:21 ` [PATCH v2 06/15] KVM: arm64: Introduce new MMIO region for the ITS base address Andre Przywara
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

Currently we initialize all the possible GIC frame addresses in one
function, without looking at the specific GIC model we instantiate
for the guest.
As this gets confusing when adding another VGIC model later, lets
move these initializations into the respective model's init functions.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic-v2-emul.c | 3 +++
 virt/kvm/arm/vgic-v3-emul.c | 3 +++
 virt/kvm/arm/vgic.c         | 3 ---
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c
index 1390797..8faa28c 100644
--- a/virt/kvm/arm/vgic-v2-emul.c
+++ b/virt/kvm/arm/vgic-v2-emul.c
@@ -567,6 +567,9 @@ void vgic_v2_init_emulation(struct kvm *kvm)
 	dist->vm_ops.init_model = vgic_v2_init_model;
 	dist->vm_ops.map_resources = vgic_v2_map_resources;
 
+	dist->vgic_cpu_base = VGIC_ADDR_UNDEF;
+	dist->vgic_dist_base = VGIC_ADDR_UNDEF;
+
 	kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
 }
 
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index d2eeb20..1f42348 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -885,6 +885,9 @@ void vgic_v3_init_emulation(struct kvm *kvm)
 	dist->vm_ops.destroy_model = vgic_v3_destroy_model;
 	dist->vm_ops.map_resources = vgic_v3_map_resources;
 
+	dist->vgic_dist_base = VGIC_ADDR_UNDEF;
+	dist->vgic_redist_base = VGIC_ADDR_UNDEF;
+
 	kvm->arch.max_vcpus = KVM_MAX_VCPUS;
 }
 
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index cc8f5ed..59f1801 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1830,9 +1830,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 	kvm->arch.vgic.in_kernel = true;
 	kvm->arch.vgic.vgic_model = type;
 	kvm->arch.vgic.vctrl_base = vgic->vctrl_base;
-	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
-	kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
-	kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
 
 out_unlock:
 	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 06/15] KVM: arm64: Introduce new MMIO region for the ITS base address
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (4 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 05/15] KVM: arm/arm64: make GIC frame address initialization model specific Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-08-13 12:17   ` Eric Auger
  2015-07-10 14:21 ` [PATCH v2 07/15] KVM: arm64: handle ITS related GICv3 redistributor registers Andre Przywara
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

The ARM GICv3 ITS controller requires a separate register frame to
cover ITS specific registers. Add a new VGIC address type and store
the address in a field in the vgic_dist structure.
Provide a function to check whether userland has provided the address,
so ITS functionality can be guarded by that check.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 Documentation/virtual/kvm/devices/arm-vgic.txt |  9 +++++++++
 arch/arm64/include/uapi/asm/kvm.h              |  2 ++
 include/kvm/arm_vgic.h                         |  3 +++
 virt/kvm/arm/vgic-v3-emul.c                    |  2 ++
 virt/kvm/arm/vgic.c                            | 16 ++++++++++++++++
 virt/kvm/arm/vgic.h                            |  1 +
 6 files changed, 33 insertions(+)

diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
index 3fb9054..ec715f9e 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic.txt
@@ -39,6 +39,15 @@ Groups:
       Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
       This address needs to be 64K aligned.
 
+    KVM_VGIC_V3_ADDR_TYPE_ITS (rw, 64-bit)
+      Base address in the guest physical address space of the GICv3 ITS
+      control register frame. The ITS allows MSI(-X) interrupts to be
+      injected into guests. This extension is optional, if the kernel
+      does not support the ITS, the call returns -ENODEV.
+      This memory is solely for the guest to access the ITS control
+      registers and does not cover the ITS translation register.
+      Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
+      This address needs to be 64K aligned and the region covers 64 KByte.
 
   KVM_DEV_ARM_VGIC_GRP_DIST_REGS
   Attributes:
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index d268320..a89b407c 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -81,9 +81,11 @@ struct kvm_regs {
 /* Supported VGICv3 address types  */
 #define KVM_VGIC_V3_ADDR_TYPE_DIST	2
 #define KVM_VGIC_V3_ADDR_TYPE_REDIST	3
+#define KVM_VGIC_V3_ADDR_TYPE_ITS	4
 
 #define KVM_VGIC_V3_DIST_SIZE		SZ_64K
 #define KVM_VGIC_V3_REDIST_SIZE		(2 * SZ_64K)
+#define KVM_VGIC_V3_ITS_SIZE		SZ_64K
 
 #define KVM_ARM_VCPU_POWER_OFF		0 /* CPU is started in OFF state */
 #define KVM_ARM_VCPU_EL1_32BIT		1 /* CPU running a 32bit VM */
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index b18e2c5..3ee063b 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -178,6 +178,9 @@ struct vgic_dist {
 		phys_addr_t		vgic_redist_base;
 	};
 
+	/* The base address of the ITS control register frame */
+	phys_addr_t		vgic_its_base;
+
 	/* Distributor enabled */
 	u32			enabled;
 
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index 1f42348..a8cf669 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -887,6 +887,7 @@ void vgic_v3_init_emulation(struct kvm *kvm)
 
 	dist->vgic_dist_base = VGIC_ADDR_UNDEF;
 	dist->vgic_redist_base = VGIC_ADDR_UNDEF;
+	dist->vgic_its_base = VGIC_ADDR_UNDEF;
 
 	kvm->arch.max_vcpus = KVM_MAX_VCPUS;
 }
@@ -1059,6 +1060,7 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 			return -ENXIO;
 		case KVM_VGIC_V3_ADDR_TYPE_DIST:
 		case KVM_VGIC_V3_ADDR_TYPE_REDIST:
+		case KVM_VGIC_V3_ADDR_TYPE_ITS:
 			return 0;
 		}
 		break;
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 59f1801..15e447f 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -930,6 +930,16 @@ int vgic_register_kvm_io_dev(struct kvm *kvm, gpa_t base, int len,
 	return ret;
 }
 
+bool vgic_has_its(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	if (dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
+		return false;
+
+	return !IS_VGIC_ADDR_UNDEF(dist->vgic_its_base);
+}
+
 static int vgic_nr_shared_irqs(struct vgic_dist *dist)
 {
 	return dist->nr_irqs - VGIC_NR_PRIVATE_IRQS;
@@ -1927,6 +1937,12 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
 		block_size = KVM_VGIC_V3_REDIST_SIZE;
 		alignment = SZ_64K;
 		break;
+	case KVM_VGIC_V3_ADDR_TYPE_ITS:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
+		addr_ptr = &vgic->vgic_its_base;
+		block_size = KVM_VGIC_V3_ITS_SIZE;
+		alignment = SZ_64K;
+		break;
 #endif
 	default:
 		r = -ENODEV;
diff --git a/virt/kvm/arm/vgic.h b/virt/kvm/arm/vgic.h
index 0df74cb..a093f5c 100644
--- a/virt/kvm/arm/vgic.h
+++ b/virt/kvm/arm/vgic.h
@@ -136,5 +136,6 @@ int vgic_get_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr);
 int vgic_init(struct kvm *kvm);
 void vgic_v2_init_emulation(struct kvm *kvm);
 void vgic_v3_init_emulation(struct kvm *kvm);
+bool vgic_has_its(struct kvm *kvm);
 
 #endif
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 07/15] KVM: arm64: handle ITS related GICv3 redistributor registers
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (5 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 06/15] KVM: arm64: Introduce new MMIO region for the ITS base address Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-08-13 12:17   ` Eric Auger
  2015-07-10 14:21 ` [PATCH v2 08/15] KVM: arm64: introduce ITS emulation file with stub functions Andre Przywara
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

In the GICv3 redistributor there are the PENDBASER and PROPBASER
registers which we did not emulate so far, as they only make sense
when having an ITS. In preparation for that emulate those MMIO
accesses by storing the 64-bit data written into it into a variable
which we later read in the ITS emulation.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h      |  8 ++++++++
 virt/kvm/arm/vgic-v3-emul.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic.c         | 35 +++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic.h         |  4 ++++
 4 files changed, 91 insertions(+)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 3ee063b..8c6cb0e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -256,6 +256,14 @@ struct vgic_dist {
 	struct vgic_vm_ops	vm_ops;
 	struct vgic_io_device	dist_iodev;
 	struct vgic_io_device	*redist_iodevs;
+
+	/* Address of LPI configuration table shared by all redistributors */
+	u64			propbaser;
+
+	/* Addresses of LPI pending tables per redistributor */
+	u64			*pendbaser;
+
+	bool			lpis_enabled;
 };
 
 struct vgic_v2_cpu_if {
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index a8cf669..5269ad1 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -651,6 +651,38 @@ static bool handle_mmio_cfg_reg_redist(struct kvm_vcpu *vcpu,
 	return vgic_handle_cfg_reg(reg, mmio, offset);
 }
 
+/* We don't trigger any actions here, just store the register value */
+static bool handle_mmio_propbaser_redist(struct kvm_vcpu *vcpu,
+					 struct kvm_exit_mmio *mmio,
+					 phys_addr_t offset)
+{
+	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+	int mode = ACCESS_READ_VALUE;
+
+	/* Storing a value with LPIs already enabled is undefined */
+	mode |= dist->lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
+	vgic_handle_base_register(vcpu, mmio, offset, &dist->propbaser, mode);
+
+	return false;
+}
+
+/* We don't trigger any actions here, just store the register value */
+static bool handle_mmio_pendbaser_redist(struct kvm_vcpu *vcpu,
+					 struct kvm_exit_mmio *mmio,
+					 phys_addr_t offset)
+{
+	struct kvm_vcpu *rdvcpu = mmio->private;
+	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+	int mode = ACCESS_READ_VALUE;
+
+	/* Storing a value with LPIs already enabled is undefined */
+	mode |= dist->lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
+	vgic_handle_base_register(vcpu, mmio, offset,
+				  &dist->pendbaser[rdvcpu->vcpu_id], mode);
+
+	return false;
+}
+
 #define SGI_base(x) ((x) + SZ_64K)
 
 static const struct vgic_io_range vgic_redist_ranges[] = {
@@ -679,6 +711,18 @@ static const struct vgic_io_range vgic_redist_ranges[] = {
 		.handle_mmio    = handle_mmio_raz_wi,
 	},
 	{
+		.base		= GICR_PENDBASER,
+		.len		= 0x08,
+		.bits_per_irq	= 0,
+		.handle_mmio	= handle_mmio_pendbaser_redist,
+	},
+	{
+		.base		= GICR_PROPBASER,
+		.len		= 0x08,
+		.bits_per_irq	= 0,
+		.handle_mmio	= handle_mmio_propbaser_redist,
+	},
+	{
 		.base           = GICR_IDREGS,
 		.len            = 0x30,
 		.bits_per_irq   = 0,
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 15e447f..49ee92b 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -446,6 +446,41 @@ void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
 	}
 }
 
+/* handle a 64-bit register access */
+void vgic_handle_base_register(struct kvm_vcpu *vcpu,
+			       struct kvm_exit_mmio *mmio,
+			       phys_addr_t offset, u64 *basereg,
+			       int mode)
+{
+	u32 reg;
+	u64 breg;
+
+	switch (offset & ~3) {
+	case 0x00:
+		breg = *basereg;
+		reg = lower_32_bits(breg);
+		vgic_reg_access(mmio, &reg, offset & 3, mode);
+		if (mmio->is_write && (mode & ACCESS_WRITE_VALUE)) {
+			breg &= GENMASK_ULL(63, 32);
+			breg |= reg;
+			*basereg = breg;
+		}
+		break;
+	case 0x04:
+		breg = *basereg;
+		reg = upper_32_bits(breg);
+		vgic_reg_access(mmio, &reg, offset & 3, mode);
+		if (mmio->is_write && (mode & ACCESS_WRITE_VALUE)) {
+			breg  = lower_32_bits(breg);
+			breg |= (u64)reg << 32;
+			*basereg = breg;
+		}
+		break;
+	}
+}
+
+
+
 bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
 			phys_addr_t offset)
 {
diff --git a/virt/kvm/arm/vgic.h b/virt/kvm/arm/vgic.h
index a093f5c..b2d791c 100644
--- a/virt/kvm/arm/vgic.h
+++ b/virt/kvm/arm/vgic.h
@@ -71,6 +71,10 @@ void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
 		     phys_addr_t offset, int mode);
 bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
 			phys_addr_t offset);
+void vgic_handle_base_register(struct kvm_vcpu *vcpu,
+			       struct kvm_exit_mmio *mmio,
+			       phys_addr_t offset, u64 *basereg,
+			       int mode);
 
 static inline
 u32 mmio_data_read(struct kvm_exit_mmio *mmio, u32 mask)
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 08/15] KVM: arm64: introduce ITS emulation file with stub functions
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (6 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 07/15] KVM: arm64: handle ITS related GICv3 redistributor registers Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-08-13 12:48   ` Eric Auger
  2015-07-10 14:21 ` [PATCH v2 09/15] KVM: arm64: implement basic ITS register handlers Andre Przywara
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

The ARM GICv3 ITS emulation code goes into a separate file, but
needs to be connected to the GICv3 emulation, of which it is an
option.
Introduce the skeleton with function stubs to be filled later.
Introduce the basic ITS data structure and initialize it, but don't
return any success yet, as we are not yet ready for the show.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm64/kvm/Makefile            |   1 +
 include/kvm/arm_vgic.h             |   6 ++
 include/linux/irqchip/arm-gic-v3.h |   1 +
 virt/kvm/arm/its-emul.c            | 125 +++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h            |  35 +++++++++++
 virt/kvm/arm/vgic-v3-emul.c        |  24 ++++++-
 6 files changed, 189 insertions(+), 3 deletions(-)
 create mode 100644 virt/kvm/arm/its-emul.c
 create mode 100644 virt/kvm/arm/its-emul.h

diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index f90f4aa..9803307 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -25,5 +25,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
 kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v2-switch.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/its-emul.o
 kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v3-switch.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 8c6cb0e..9e9d4aa 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -156,6 +156,11 @@ struct vgic_io_device {
 	struct kvm_io_device dev;
 };
 
+struct vgic_its {
+	bool			enabled;
+	spinlock_t		lock;
+};
+
 struct vgic_dist {
 	spinlock_t		lock;
 	bool			in_kernel;
@@ -264,6 +269,7 @@ struct vgic_dist {
 	u64			*pendbaser;
 
 	bool			lpis_enabled;
+	struct vgic_its		its;
 };
 
 struct vgic_v2_cpu_if {
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index ffbc034..df4e527 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -177,6 +177,7 @@
 #define GITS_CWRITER			0x0088
 #define GITS_CREADR			0x0090
 #define GITS_BASER			0x0100
+#define GITS_IDREGS_BASE		0xffd0
 #define GITS_PIDR2			GICR_PIDR2
 
 #define GITS_TRANSLATER			0x10040
diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
new file mode 100644
index 0000000..659dd39
--- /dev/null
+++ b/virt/kvm/arm/its-emul.c
@@ -0,0 +1,125 @@
+/*
+ * GICv3 ITS emulation
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ * Author: Andre Przywara <andre.przywara@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/cpu.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/interrupt.h>
+
+#include <linux/irqchip/arm-gic-v3.h>
+#include <kvm/arm_vgic.h>
+
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
+
+#include "vgic.h"
+#include "its-emul.h"
+
+static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
+				  struct kvm_exit_mmio *mmio,
+				  phys_addr_t offset)
+{
+	return false;
+}
+
+static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
+				    struct kvm_exit_mmio *mmio,
+				    phys_addr_t offset)
+{
+	return false;
+}
+
+static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
+				    struct kvm_exit_mmio *mmio,
+				    phys_addr_t offset)
+{
+	return false;
+}
+
+static bool handle_mmio_gits_cwriter(struct kvm_vcpu *vcpu,
+				     struct kvm_exit_mmio *mmio,
+				     phys_addr_t offset)
+{
+	return false;
+}
+
+static bool handle_mmio_gits_creadr(struct kvm_vcpu *vcpu,
+				    struct kvm_exit_mmio *mmio,
+				    phys_addr_t offset)
+{
+	return false;
+}
+
+static const struct vgic_io_range vgicv3_its_ranges[] = {
+	{
+		.base		= GITS_CTLR,
+		.len		= 0x10,
+		.bits_per_irq	= 0,
+		.handle_mmio	= handle_mmio_misc_gits,
+	},
+	{
+		.base		= GITS_CBASER,
+		.len		= 0x08,
+		.bits_per_irq	= 0,
+		.handle_mmio	= handle_mmio_gits_cbaser,
+	},
+	{
+		.base		= GITS_CWRITER,
+		.len		= 0x08,
+		.bits_per_irq	= 0,
+		.handle_mmio	= handle_mmio_gits_cwriter,
+	},
+	{
+		.base		= GITS_CREADR,
+		.len		= 0x08,
+		.bits_per_irq	= 0,
+		.handle_mmio	= handle_mmio_gits_creadr,
+	},
+	{
+		/* We don't need any memory from the guest. */
+		.base		= GITS_BASER,
+		.len		= 0x40,
+		.bits_per_irq	= 0,
+		.handle_mmio	= handle_mmio_raz_wi,
+	},
+	{
+		.base		= GITS_IDREGS_BASE,
+		.len		= 0x30,
+		.bits_per_irq	= 0,
+		.handle_mmio	= handle_mmio_gits_idregs,
+	},
+};
+
+/* This is called on setting the LPI enable bit in the redistributor. */
+void vgic_enable_lpis(struct kvm_vcpu *vcpu)
+{
+}
+
+int vits_init(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct vgic_its *its = &dist->its;
+
+	spin_lock_init(&its->lock);
+
+	its->enabled = false;
+
+	return -ENXIO;
+}
diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
new file mode 100644
index 0000000..5dc8e2f
--- /dev/null
+++ b/virt/kvm/arm/its-emul.h
@@ -0,0 +1,35 @@
+/*
+ * GICv3 ITS emulation definitions
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ * Author: Andre Przywara <andre.przywara@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __KVM_ITS_EMUL_H__
+#define __KVM_ITS_EMUL_H__
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
+
+#include "vgic.h"
+
+void vgic_enable_lpis(struct kvm_vcpu *vcpu);
+int vits_init(struct kvm *kvm);
+
+#endif
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index 5269ad1..f5865e7 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -48,6 +48,7 @@
 #include <asm/kvm_mmu.h>
 
 #include "vgic.h"
+#include "its-emul.h"
 
 static bool handle_mmio_rao_wi(struct kvm_vcpu *vcpu,
 			       struct kvm_exit_mmio *mmio, phys_addr_t offset)
@@ -530,9 +531,20 @@ static bool handle_mmio_ctlr_redist(struct kvm_vcpu *vcpu,
 				    struct kvm_exit_mmio *mmio,
 				    phys_addr_t offset)
 {
-	/* since we don't support LPIs, this register is zero for now */
-	vgic_reg_access(mmio, NULL, offset,
-			ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
+	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+	u32 reg;
+
+	if (!vgic_has_its(vcpu->kvm)) {
+		vgic_reg_access(mmio, NULL, offset,
+				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
+		return false;
+	}
+	reg = dist->lpis_enabled ? GICR_CTLR_ENABLE_LPIS : 0;
+	vgic_reg_access(mmio, &reg, offset,
+			ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
+	if (!dist->lpis_enabled && (reg & GICR_CTLR_ENABLE_LPIS)) {
+		/* Eventually do something */
+	}
 	return false;
 }
 
@@ -861,6 +873,12 @@ static int vgic_v3_map_resources(struct kvm *kvm,
 		rdbase += GIC_V3_REDIST_SIZE;
 	}
 
+	if (vgic_has_its(kvm)) {
+		ret = vits_init(kvm);
+		if (ret)
+			goto out_unregister;
+	}
+
 	dist->redist_iodevs = iodevs;
 	dist->ready = true;
 	goto out;
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 09/15] KVM: arm64: implement basic ITS register handlers
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (7 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 08/15] KVM: arm64: introduce ITS emulation file with stub functions Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-08-13 15:25   ` Eric Auger
  2015-10-02  7:51   ` Pavel Fedin
  2015-07-10 14:21 ` [PATCH v2 10/15] KVM: arm64: add data structures to model ITS interrupt translation Andre Przywara
                   ` (7 subsequent siblings)
  16 siblings, 2 replies; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

Add emulation for some basic MMIO registers used in the ITS emulation.
This includes:
- GITS_{CTLR,TYPER,IIDR}
- ID registers
- GITS_{CBASER,CREADR,CWRITER}
  those implement the ITS command buffer handling

Most of the handlers are pretty straight forward, but CWRITER goes
some extra miles to allow fine grained locking. The idea here
is to let only the first instance iterate through the command ring
buffer, CWRITER accesses on other VCPUs meanwhile will be picked up
by that first instance and handled as well. The ITS lock is thus only
hold for very small periods of time and is dropped before the actual
command handler is called.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h             |   3 +
 include/linux/irqchip/arm-gic-v3.h |   8 ++
 virt/kvm/arm/its-emul.c            | 205 +++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h            |   1 +
 virt/kvm/arm/vgic-v3-emul.c        |   2 +
 5 files changed, 219 insertions(+)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 9e9d4aa..b432055 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -159,6 +159,9 @@ struct vgic_io_device {
 struct vgic_its {
 	bool			enabled;
 	spinlock_t		lock;
+	u64			cbaser;
+	int			creadr;
+	int			cwriter;
 };
 
 struct vgic_dist {
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index df4e527..0b450c7 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -179,15 +179,23 @@
 #define GITS_BASER			0x0100
 #define GITS_IDREGS_BASE		0xffd0
 #define GITS_PIDR2			GICR_PIDR2
+#define GITS_PIDR4			0xffd0
+#define GITS_CIDR0			0xfff0
+#define GITS_CIDR1			0xfff4
+#define GITS_CIDR2			0xfff8
+#define GITS_CIDR3			0xfffc
 
 #define GITS_TRANSLATER			0x10040
 
 #define GITS_CTLR_ENABLE		(1U << 0)
 #define GITS_CTLR_QUIESCENT		(1U << 31)
 
+#define GITS_TYPER_PLPIS		(1UL << 0)
+#define GITS_TYPER_IDBITS_SHIFT		8
 #define GITS_TYPER_DEVBITS_SHIFT	13
 #define GITS_TYPER_DEVBITS(r)		((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
 #define GITS_TYPER_PTA			(1UL << 19)
+#define GITS_TYPER_HWCOLLCNT_SHIFT	24
 
 #define GITS_CBASER_VALID		(1UL << 63)
 #define GITS_CBASER_nCnB		(0UL << 59)
diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index 659dd39..b498f06 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -32,10 +32,62 @@
 #include "vgic.h"
 #include "its-emul.h"
 
+#define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
+
+/* The distributor lock is held by the VGIC MMIO handler. */
 static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
 				  struct kvm_exit_mmio *mmio,
 				  phys_addr_t offset)
 {
+	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
+	u32 reg;
+	bool was_enabled;
+
+	switch (offset & ~3) {
+	case 0x00:		/* GITS_CTLR */
+		/* We never defer any command execution. */
+		reg = GITS_CTLR_QUIESCENT;
+		if (its->enabled)
+			reg |= GITS_CTLR_ENABLE;
+		was_enabled = its->enabled;
+		vgic_reg_access(mmio, &reg, offset & 3,
+				ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
+		its->enabled = !!(reg & GITS_CTLR_ENABLE);
+		return !was_enabled && its->enabled;
+	case 0x04:		/* GITS_IIDR */
+		reg = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+		vgic_reg_access(mmio, &reg, offset & 3,
+				ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
+		break;
+	case 0x08:		/* GITS_TYPER */
+		/*
+		 * We use linear CPU numbers for redistributor addressing,
+		 * so GITS_TYPER.PTA is 0.
+		 * To avoid memory waste on the guest side, we keep the
+		 * number of IDBits and DevBits low for the time being.
+		 * This could later be made configurable by userland.
+		 * Since we have all collections in linked list, we claim
+		 * that we can hold all of the collection tables in our
+		 * own memory and that the ITT entry size is 1 byte (the
+		 * smallest possible one).
+		 */
+		reg = GITS_TYPER_PLPIS;
+		reg |= 0xff << GITS_TYPER_HWCOLLCNT_SHIFT;
+		reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT;
+		reg |= 0x0f << GITS_TYPER_IDBITS_SHIFT;
+		vgic_reg_access(mmio, &reg, offset & 3,
+				ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
+		break;
+	case 0x0c:
+		/* The upper 32bits of TYPER are all 0 for the time being.
+		 * Should we need more than 256 collections, we can enable
+		 * some bits in here.
+		 */
+		vgic_reg_access(mmio, NULL, offset & 3,
+				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
+		break;
+	}
+
 	return false;
 }
 
@@ -43,20 +95,142 @@ static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
 				    struct kvm_exit_mmio *mmio,
 				    phys_addr_t offset)
 {
+	u32 reg = 0;
+	int idreg = (offset & ~3) + GITS_IDREGS_BASE;
+
+	switch (idreg) {
+	case GITS_PIDR2:
+		reg = GIC_PIDR2_ARCH_GICv3;
+		break;
+	case GITS_PIDR4:
+		/* This is a 64K software visible page */
+		reg = 0x40;
+		break;
+	/* Those are the ID registers for (any) GIC. */
+	case GITS_CIDR0:
+		reg = 0x0d;
+		break;
+	case GITS_CIDR1:
+		reg = 0xf0;
+		break;
+	case GITS_CIDR2:
+		reg = 0x05;
+		break;
+	case GITS_CIDR3:
+		reg = 0xb1;
+		break;
+	}
+	vgic_reg_access(mmio, &reg, offset & 3,
+			ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
 	return false;
 }
 
+static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
+{
+	return -ENODEV;
+}
+
 static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
 				    struct kvm_exit_mmio *mmio,
 				    phys_addr_t offset)
 {
+	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
+	int mode = ACCESS_READ_VALUE;
+
+	mode |= its->enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
+
+	vgic_handle_base_register(vcpu, mmio, offset, &its->cbaser, mode);
+
+	/* Writing CBASER resets the read pointer. */
+	if (mmio->is_write)
+		its->creadr = 0;
+
 	return false;
 }
 
+static int its_cmd_buffer_size(struct kvm *kvm)
+{
+	struct vgic_its *its = &kvm->arch.vgic.its;
+
+	return ((its->cbaser & 0xff) + 1) << 12;
+}
+
+static gpa_t its_cmd_buffer_base(struct kvm *kvm)
+{
+	struct vgic_its *its = &kvm->arch.vgic.its;
+
+	return BASER_BASE_ADDRESS(its->cbaser);
+}
+
+/*
+ * By writing to CWRITER the guest announces new commands to be processed.
+ * Since we cannot read from guest memory inside the ITS spinlock, we
+ * iterate over the command buffer (with the lock dropped) until the read
+ * pointer matches the write pointer. Other VCPUs writing this register in the
+ * meantime will just update the write pointer, leaving the command
+ * processing to the first instance of the function.
+ */
 static bool handle_mmio_gits_cwriter(struct kvm_vcpu *vcpu,
 				     struct kvm_exit_mmio *mmio,
 				     phys_addr_t offset)
 {
+	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
+	gpa_t cbaser = its_cmd_buffer_base(vcpu->kvm);
+	u64 cmd_buf[4];
+	u32 reg;
+	bool finished;
+
+	/* The upper 32 bits are RES0 */
+	if ((offset & ~3) == 0x04) {
+		vgic_reg_access(mmio, &reg, offset & 3,
+				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
+		return false;
+	}
+
+	reg = its->cwriter & 0xfffe0;
+	vgic_reg_access(mmio, &reg, offset & 3,
+			ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
+	if (!mmio->is_write)
+		return false;
+
+	reg &= 0xfffe0;
+	if (reg > its_cmd_buffer_size(vcpu->kvm))
+		return false;
+
+	spin_lock(&its->lock);
+
+	/*
+	 * If there is still another VCPU handling commands, let this
+	 * one pick up the new CWRITER and process our new commands as well.
+	 */
+	finished = (its->cwriter != its->creadr);
+	its->cwriter = reg;
+
+	spin_unlock(&its->lock);
+
+	while (!finished) {
+		int ret = kvm_read_guest(vcpu->kvm, cbaser + its->creadr,
+					 cmd_buf, 32);
+		if (ret) {
+			/*
+			 * Gah, we are screwed. Reset CWRITER to that command
+			 * that we have finished processing and return.
+			 */
+			spin_lock(&its->lock);
+			its->cwriter = its->creadr;
+			spin_unlock(&its->lock);
+			break;
+		}
+		vits_handle_command(vcpu, cmd_buf);
+
+		spin_lock(&its->lock);
+		its->creadr += 32;
+		if (its->creadr == its_cmd_buffer_size(vcpu->kvm))
+			its->creadr = 0;
+		finished = (its->creadr == its->cwriter);
+		spin_unlock(&its->lock);
+	}
+
 	return false;
 }
 
@@ -64,6 +238,20 @@ static bool handle_mmio_gits_creadr(struct kvm_vcpu *vcpu,
 				    struct kvm_exit_mmio *mmio,
 				    phys_addr_t offset)
 {
+	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
+	u32 reg;
+
+	switch (offset & ~3) {
+	case 0x00:
+		reg = its->creadr & 0xfffe0;
+		vgic_reg_access(mmio, &reg, offset & 3,
+				ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
+		break;
+	case 0x04:
+		vgic_reg_access(mmio, &reg, offset & 3,
+				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
+		break;
+	}
 	return false;
 }
 
@@ -117,9 +305,26 @@ int vits_init(struct kvm *kvm)
 	struct vgic_dist *dist = &kvm->arch.vgic;
 	struct vgic_its *its = &dist->its;
 
+	dist->pendbaser = kmalloc(sizeof(u64) * dist->nr_cpus, GFP_KERNEL);
+	if (!dist->pendbaser)
+		return -ENOMEM;
+
 	spin_lock_init(&its->lock);
 
 	its->enabled = false;
 
 	return -ENXIO;
 }
+
+void vits_destroy(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct vgic_its *its = &dist->its;
+
+	if (!vgic_has_its(kvm))
+		return;
+
+	kfree(dist->pendbaser);
+
+	its->enabled = false;
+}
diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
index 5dc8e2f..472a6d0 100644
--- a/virt/kvm/arm/its-emul.h
+++ b/virt/kvm/arm/its-emul.h
@@ -31,5 +31,6 @@
 
 void vgic_enable_lpis(struct kvm_vcpu *vcpu);
 int vits_init(struct kvm *kvm);
+void vits_destroy(struct kvm *kvm);
 
 #endif
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index f5865e7..49be3c3 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -928,6 +928,8 @@ static void vgic_v3_destroy_model(struct kvm *kvm)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
 
+	vits_destroy(kvm);
+
 	kfree(dist->irq_spi_mpidr);
 	dist->irq_spi_mpidr = NULL;
 }
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 10/15] KVM: arm64: add data structures to model ITS interrupt translation
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (8 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 09/15] KVM: arm64: implement basic ITS register handlers Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-08-13 15:46   ` Eric Auger
  2015-07-10 14:21 ` [PATCH v2 11/15] KVM: arm64: handle pending bit for LPIs in ITS emulation Andre Przywara
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

The GICv3 Interrupt Translation Service (ITS) uses tables in memory
to allow a sophisticated interrupt routing. It features device tables,
an interrupt table per device and a table connecting "collections" to
actual CPUs (aka. redistributors in the GICv3 lingo).
Since the interrupt numbers for the LPIs are allocated quite sparsely
and the range can be quite huge (8192 LPIs being the minimum), using
bitmaps or arrays for storing information is a waste of memory.
We use linked lists instead, which we iterate linearily. This works
very well with the actual number of LPIs/MSIs in the guest being
quite low. Should the number of LPIs exceed the number where iterating
through lists seems acceptable, we can later revisit this and use more
efficient data structures.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h  |  3 +++
 virt/kvm/arm/its-emul.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index b432055..1648668 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -25,6 +25,7 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <kvm/iodev.h>
+#include <linux/list.h>
 
 #define VGIC_NR_IRQS_LEGACY	256
 #define VGIC_NR_SGIS		16
@@ -162,6 +163,8 @@ struct vgic_its {
 	u64			cbaser;
 	int			creadr;
 	int			cwriter;
+	struct list_head	device_list;
+	struct list_head	collection_list;
 };
 
 struct vgic_dist {
diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index b498f06..7f217fa 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -21,6 +21,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/interrupt.h>
+#include <linux/list.h>
 
 #include <linux/irqchip/arm-gic-v3.h>
 #include <kvm/arm_vgic.h>
@@ -32,6 +33,25 @@
 #include "vgic.h"
 #include "its-emul.h"
 
+struct its_device {
+	struct list_head dev_list;
+	struct list_head itt;
+	u32 device_id;
+};
+
+struct its_collection {
+	struct list_head coll_list;
+	u32 collection_id;
+	u32 target_addr;
+};
+
+struct its_itte {
+	struct list_head itte_list;
+	struct its_collection *collection;
+	u32 lpi;
+	u32 event_id;
+};
+
 #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
 
 /* The distributor lock is held by the VGIC MMIO handler. */
@@ -311,6 +331,9 @@ int vits_init(struct kvm *kvm)
 
 	spin_lock_init(&its->lock);
 
+	INIT_LIST_HEAD(&its->device_list);
+	INIT_LIST_HEAD(&its->collection_list);
+
 	its->enabled = false;
 
 	return -ENXIO;
@@ -320,11 +343,36 @@ void vits_destroy(struct kvm *kvm)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
 	struct vgic_its *its = &dist->its;
+	struct its_device *dev;
+	struct its_itte *itte;
+	struct list_head *dev_cur, *dev_temp;
+	struct list_head *cur, *temp;
 
 	if (!vgic_has_its(kvm))
 		return;
 
+	if (!its->device_list.next)
+		return;
+
+	spin_lock(&its->lock);
+	list_for_each_safe(dev_cur, dev_temp, &its->device_list) {
+		dev = container_of(dev_cur, struct its_device, dev_list);
+		list_for_each_safe(cur, temp, &dev->itt) {
+			itte = (container_of(cur, struct its_itte, itte_list));
+			list_del(cur);
+			kfree(itte);
+		}
+		list_del(dev_cur);
+		kfree(dev);
+	}
+
+	list_for_each_safe(cur, temp, &its->collection_list) {
+		list_del(cur);
+		kfree(container_of(cur, struct its_collection, coll_list));
+	}
+
 	kfree(dist->pendbaser);
 
 	its->enabled = false;
+	spin_unlock(&its->lock);
 }
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 11/15] KVM: arm64: handle pending bit for LPIs in ITS emulation
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (9 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 10/15] KVM: arm64: add data structures to model ITS interrupt translation Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-08-14 11:58   ` Eric Auger
  2015-10-07  8:39   ` Pavel Fedin
  2015-07-10 14:21 ` [PATCH v2 12/15] KVM: arm64: sync LPI configuration and pending tables Andre Przywara
                   ` (5 subsequent siblings)
  16 siblings, 2 replies; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

As the actual LPI number in a guest can be quite high, but is mostly
assigned using a very sparse allocation scheme, bitmaps and arrays
for storing the virtual interrupt status are a waste of memory.
We use our equivalent of the "Interrupt Translation Table Entry"
(ITTE) to hold this extra status information for a virtual LPI.
As the normal VGIC code cannot use it's fancy bitmaps to manage
pending interrupts, we provide a hook in the VGIC code to let the
ITS emulation handle the list register queueing itself.
LPIs are located in a separate number range (>=8192), so
distinguishing them is easy. With LPIs being only edge-triggered, we
get away with a less complex IRQ handling.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h      |  2 ++
 virt/kvm/arm/its-emul.c     | 71 ++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h     |  3 ++
 virt/kvm/arm/vgic-v3-emul.c |  2 ++
 virt/kvm/arm/vgic.c         | 72 ++++++++++++++++++++++++++++++++++-----------
 5 files changed, 133 insertions(+), 17 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 1648668..2a67a10 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -147,6 +147,8 @@ struct vgic_vm_ops {
 	int	(*init_model)(struct kvm *);
 	void	(*destroy_model)(struct kvm *);
 	int	(*map_resources)(struct kvm *, const struct vgic_params *);
+	bool	(*queue_lpis)(struct kvm_vcpu *);
+	void	(*unqueue_lpi)(struct kvm_vcpu *, int irq);
 };
 
 struct vgic_io_device {
diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index 7f217fa..b9c40d7 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -50,8 +50,26 @@ struct its_itte {
 	struct its_collection *collection;
 	u32 lpi;
 	u32 event_id;
+	bool enabled;
+	unsigned long *pending;
 };
 
+#define for_each_lpi(dev, itte, kvm) \
+	list_for_each_entry(dev, &(kvm)->arch.vgic.its.device_list, dev_list) \
+		list_for_each_entry(itte, &(dev)->itt, itte_list)
+
+static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
+{
+	struct its_device *device;
+	struct its_itte *itte;
+
+	for_each_lpi(device, itte, kvm) {
+		if (itte->lpi == lpi)
+			return itte;
+	}
+	return NULL;
+}
+
 #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
 
 /* The distributor lock is held by the VGIC MMIO handler. */
@@ -145,6 +163,59 @@ static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
 	return false;
 }
 
+/*
+ * Find all enabled and pending LPIs and queue them into the list
+ * registers.
+ * The dist lock is held by the caller.
+ */
+bool vits_queue_lpis(struct kvm_vcpu *vcpu)
+{
+	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
+	struct its_device *device;
+	struct its_itte *itte;
+	bool ret = true;
+
+	if (!vgic_has_its(vcpu->kvm))
+		return true;
+	if (!its->enabled || !vcpu->kvm->arch.vgic.lpis_enabled)
+		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)
+			continue;
+
+		__clear_bit(vcpu->vcpu_id, itte->pending);
+
+		ret &= vgic_queue_irq(vcpu, 0, itte->lpi);
+	}
+
+	spin_unlock(&its->lock);
+	return ret;
+}
+
+/* Called with the distributor lock held by the caller. */
+void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi)
+{
+	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
+	struct its_itte *itte;
+
+	spin_lock(&its->lock);
+
+	/* Find the right ITTE and put the pending state back in there */
+	itte = find_itte_by_lpi(vcpu->kvm, lpi);
+	if (itte)
+		__set_bit(vcpu->vcpu_id, itte->pending);
+
+	spin_unlock(&its->lock);
+}
+
 static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
 {
 	return -ENODEV;
diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
index 472a6d0..cc5d5ff 100644
--- a/virt/kvm/arm/its-emul.h
+++ b/virt/kvm/arm/its-emul.h
@@ -33,4 +33,7 @@ void vgic_enable_lpis(struct kvm_vcpu *vcpu);
 int vits_init(struct kvm *kvm);
 void vits_destroy(struct kvm *kvm);
 
+bool vits_queue_lpis(struct kvm_vcpu *vcpu);
+void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int irq);
+
 #endif
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index 49be3c3..4132c26 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -948,6 +948,8 @@ void vgic_v3_init_emulation(struct kvm *kvm)
 	dist->vm_ops.init_model = vgic_v3_init_model;
 	dist->vm_ops.destroy_model = vgic_v3_destroy_model;
 	dist->vm_ops.map_resources = vgic_v3_map_resources;
+	dist->vm_ops.queue_lpis = vits_queue_lpis;
+	dist->vm_ops.unqueue_lpi = vits_unqueue_lpi;
 
 	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 49ee92b..9dfd094 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -95,6 +95,20 @@ static bool queue_sgi(struct kvm_vcpu *vcpu, int irq)
 	return vcpu->kvm->arch.vgic.vm_ops.queue_sgi(vcpu, irq);
 }
 
+static bool vgic_queue_lpis(struct kvm_vcpu *vcpu)
+{
+	if (vcpu->kvm->arch.vgic.vm_ops.queue_lpis)
+		return vcpu->kvm->arch.vgic.vm_ops.queue_lpis(vcpu);
+	else
+		return true;
+}
+
+static void vgic_unqueue_lpi(struct kvm_vcpu *vcpu, int irq)
+{
+	if (vcpu->kvm->arch.vgic.vm_ops.unqueue_lpi)
+		vcpu->kvm->arch.vgic.vm_ops.unqueue_lpi(vcpu, irq);
+}
+
 int kvm_vgic_map_resources(struct kvm *kvm)
 {
 	return kvm->arch.vgic.vm_ops.map_resources(kvm, vgic);
@@ -1135,6 +1149,10 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
 	for_each_clear_bit(lr, elrsr_ptr, vgic->nr_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)) {
 			vlr.state = 0;
 			vgic_set_lr(vcpu, lr, vlr);
@@ -1147,25 +1165,33 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
 static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
 				 int lr_nr, int sgi_source_id)
 {
+	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct vgic_lr vlr;
 
 	vlr.state = 0;
 	vlr.irq = irq;
 	vlr.source = sgi_source_id;
 
-	if (vgic_irq_is_active(vcpu, irq)) {
-		vlr.state |= LR_STATE_ACTIVE;
-		kvm_debug("Set active, clear distributor: 0x%x\n", vlr.state);
-		vgic_irq_clear_active(vcpu, irq);
-		vgic_update_state(vcpu->kvm);
-	} else if (vgic_dist_irq_is_pending(vcpu, irq)) {
-		vlr.state |= LR_STATE_PENDING;
-		kvm_debug("Set pending: 0x%x\n", vlr.state);
-	}
-
-	if (!vgic_irq_is_edge(vcpu, irq))
-		vlr.state |= LR_EOI_INT;
+	/* We care only about state for SGIs/PPIs/SPIs, not for LPIs */
+	if (irq < dist->nr_irqs) {
+		if (vgic_irq_is_active(vcpu, irq)) {
+			vlr.state |= LR_STATE_ACTIVE;
+			kvm_debug("Set active, clear distributor: 0x%x\n",
+				  vlr.state);
+			vgic_irq_clear_active(vcpu, irq);
+			vgic_update_state(vcpu->kvm);
+		} else if (vgic_dist_irq_is_pending(vcpu, irq)) {
+			vlr.state |= LR_STATE_PENDING;
+			kvm_debug("Set pending: 0x%x\n", vlr.state);
+		}
 
+		if (!vgic_irq_is_edge(vcpu, irq))
+			vlr.state |= LR_EOI_INT;
+	} else {
+		/* If this is an LPI, it can only be pending */
+		if (irq >= 8192)
+			vlr.state |= LR_STATE_PENDING;
+	}
 	vgic_set_lr(vcpu, lr_nr, vlr);
 	vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
 }
@@ -1177,7 +1203,6 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
  */
 bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
 {
-	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	u64 elrsr = vgic_get_elrsr(vcpu);
 	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
 	int lr;
@@ -1185,7 +1210,6 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
 	/* Sanitize the input... */
 	BUG_ON(sgi_source_id & ~7);
 	BUG_ON(sgi_source_id && irq >= VGIC_NR_SGIS);
-	BUG_ON(irq >= dist->nr_irqs);
 
 	kvm_debug("Queue IRQ%d\n", irq);
 
@@ -1265,8 +1289,12 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 			overflow = 1;
 	}
 
-
-
+	/*
+	 * LPIs are not mapped in our bitmaps, so we leave the iteration
+	 * to the ITS emulation code.
+	 */
+	if (!vgic_queue_lpis(vcpu))
+		overflow = 1;
 
 epilog:
 	if (overflow) {
@@ -1387,6 +1415,16 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	for_each_clear_bit(lr_nr, elrsr_ptr, vgic_cpu->nr_lr) {
 		vlr = vgic_get_lr(vcpu, lr_nr);
 
+		/* LPIs are handled separately */
+		if (vlr.irq >= 8192) {
+			/* We just need to take care about still pending LPIs */
+			if (vlr.state & LR_STATE_PENDING) {
+				vgic_unqueue_lpi(vcpu, vlr.irq);
+				pending = true;
+			}
+			continue;
+		}
+
 		BUG_ON(!(vlr.state & LR_STATE_MASK));
 		pending = true;
 
@@ -1411,7 +1449,7 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	}
 	vgic_update_state(vcpu->kvm);
 
-	/* vgic_update_state would not cover only-active IRQs */
+	/* vgic_update_state would not cover only-active IRQs or LPIs */
 	if (pending)
 		set_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu);
 }
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 12/15] KVM: arm64: sync LPI configuration and pending tables
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (10 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 11/15] KVM: arm64: handle pending bit for LPIs in ITS emulation Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-08-14 11:58   ` Eric Auger
  2015-07-10 14:21 ` [PATCH v2 13/15] KVM: arm64: implement ITS command queue command handlers Andre Przywara
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

The LPI configuration and pending tables of the GICv3 LPIs are held
in tables in (guest) memory. To achieve reasonable performance, we
cache this data in our own data structures, so we need to sync those
two views from time to time. This behaviour is well described in the
GICv3 spec and is also exercised by hardware, so the sync points are
well known.

Provide functions that read the guest memory and store the
information from the configuration and pending tables in the kernel.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h  |   2 +
 virt/kvm/arm/its-emul.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h |   3 ++
 3 files changed, 129 insertions(+)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 2a67a10..323c33a 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -167,6 +167,8 @@ struct vgic_its {
 	int			cwriter;
 	struct list_head	device_list;
 	struct list_head	collection_list;
+	/* memory used for buffering guest's memory */
+	void			*buffer_page;
 };
 
 struct vgic_dist {
diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index b9c40d7..05245cb 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -50,6 +50,7 @@ struct its_itte {
 	struct its_collection *collection;
 	u32 lpi;
 	u32 event_id;
+	u8 priority;
 	bool enabled;
 	unsigned long *pending;
 };
@@ -70,8 +71,124 @@ static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
 	return NULL;
 }
 
+#define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
+#define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
+
+/* stores the priority and enable bit for a given LPI */
+static void update_lpi_config(struct kvm *kvm, struct its_itte *itte, u8 prop)
+{
+	itte->priority = LPI_PROP_PRIORITY(prop);
+	itte->enabled  = LPI_PROP_ENABLE_BIT(prop);
+}
+
+#define GIC_LPI_OFFSET 8192
+
+/* We scan the table in chunks the size of the smallest page size */
+#define CHUNK_SIZE 4096U
+
 #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
 
+static int nr_idbits_propbase(u64 propbaser)
+{
+	int nr_idbits = (1U << (propbaser & 0x1f)) + 1;
+
+	return max(nr_idbits, INTERRUPT_ID_BITS_ITS);
+}
+
+/*
+ * Scan the whole LPI configuration table and put the LPI configuration
+ * data in our own data structures. This relies on the LPI being
+ * mapped before.
+ */
+static bool its_update_lpis_configuration(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	u8 *prop = dist->its.buffer_page;
+	u32 tsize;
+	gpa_t propbase;
+	int lpi = GIC_LPI_OFFSET;
+	struct its_itte *itte;
+	struct its_device *device;
+	int ret;
+
+	propbase = BASER_BASE_ADDRESS(dist->propbaser);
+	tsize = nr_idbits_propbase(dist->propbaser);
+
+	while (tsize > 0) {
+		int chunksize = min(tsize, CHUNK_SIZE);
+
+		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
+		if (ret)
+			return false;
+
+		spin_lock(&dist->its.lock);
+		/*
+		 * Updating the status for all allocated LPIs. We catch
+		 * those LPIs that get disabled. We really don't care
+		 * about unmapped LPIs, as they need to be updated
+		 * later manually anyway once they get mapped.
+		 */
+		for_each_lpi(device, itte, kvm) {
+			if (itte->lpi < lpi || itte->lpi >= lpi + chunksize)
+				continue;
+
+			update_lpi_config(kvm, itte, prop[itte->lpi - lpi]);
+		}
+		spin_unlock(&dist->its.lock);
+		tsize -= chunksize;
+		lpi += chunksize;
+		propbase += chunksize;
+	}
+
+	return true;
+}
+
+/*
+ * Scan the whole LPI pending table and sync the pending bit in there
+ * with our own data structures. This relies on the LPI being
+ * mapped before.
+ */
+static bool its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
+{
+	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+	unsigned long *pendmask = dist->its.buffer_page;
+	u32 nr_lpis = VITS_NR_LPIS;
+	gpa_t pendbase;
+	int lpi = 0;
+	struct its_itte *itte;
+	struct its_device *device;
+	int ret;
+	int lpi_bit, nr_bits;
+
+	pendbase = BASER_BASE_ADDRESS(dist->pendbaser[vcpu->vcpu_id]);
+
+	while (nr_lpis > 0) {
+		nr_bits = min(nr_lpis, CHUNK_SIZE * 8);
+
+		ret = kvm_read_guest(vcpu->kvm, pendbase, pendmask,
+				     nr_bits / 8);
+		if (ret)
+			return false;
+
+		spin_lock(&dist->its.lock);
+		for_each_lpi(device, itte, vcpu->kvm) {
+			lpi_bit = itte->lpi - lpi;
+			if (lpi_bit < 0 || lpi_bit >= nr_bits)
+				continue;
+			if (test_bit(lpi_bit, pendmask))
+				__set_bit(vcpu->vcpu_id, itte->pending);
+			else
+				__clear_bit(vcpu->vcpu_id, itte->pending);
+		}
+		spin_unlock(&dist->its.lock);
+		nr_lpis -= nr_bits;
+		lpi += nr_bits;
+		pendbase += nr_bits / 8;
+	}
+
+	return true;
+}
+
 /* The distributor lock is held by the VGIC MMIO handler. */
 static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
 				  struct kvm_exit_mmio *mmio,
@@ -389,6 +506,8 @@ static const struct vgic_io_range vgicv3_its_ranges[] = {
 /* This is called on setting the LPI enable bit in the redistributor. */
 void vgic_enable_lpis(struct kvm_vcpu *vcpu)
 {
+	its_update_lpis_configuration(vcpu->kvm);
+	its_sync_lpi_pending_table(vcpu);
 }
 
 int vits_init(struct kvm *kvm)
@@ -400,6 +519,10 @@ int vits_init(struct kvm *kvm)
 	if (!dist->pendbaser)
 		return -ENOMEM;
 
+	its->buffer_page = kmalloc(CHUNK_SIZE, GFP_KERNEL);
+	if (!its->buffer_page)
+		return -ENOMEM;
+
 	spin_lock_init(&its->lock);
 
 	INIT_LIST_HEAD(&its->device_list);
@@ -442,6 +565,7 @@ void vits_destroy(struct kvm *kvm)
 		kfree(container_of(cur, struct its_collection, coll_list));
 	}
 
+	kfree(its->buffer_page);
 	kfree(dist->pendbaser);
 
 	its->enabled = false;
diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
index cc5d5ff..cbc3877 100644
--- a/virt/kvm/arm/its-emul.h
+++ b/virt/kvm/arm/its-emul.h
@@ -29,6 +29,9 @@
 
 #include "vgic.h"
 
+#define INTERRUPT_ID_BITS_ITS 16
+#define VITS_NR_LPIS (1U << INTERRUPT_ID_BITS_ITS)
+
 void vgic_enable_lpis(struct kvm_vcpu *vcpu);
 int vits_init(struct kvm *kvm);
 void vits_destroy(struct kvm *kvm);
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 13/15] KVM: arm64: implement ITS command queue command handlers
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (11 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 12/15] KVM: arm64: sync LPI configuration and pending tables Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-08-17 13:33   ` Eric Auger
  2015-07-10 14:21 ` [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation Andre Przywara
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

The connection between a device, an event ID, the LPI number and the
allocated CPU is stored in in-memory tables in a GICv3, but their
format is not specified by the spec. Instead software uses a command
queue in a ring buffer to let the ITS implementation use their own
format.
Implement handlers for the various ITS commands and let them store
the requested relation into our own data structures.
To avoid kmallocs inside the ITS spinlock, we preallocate possibly
needed memory outside of the lock and free that if it turns out to
be not needed (mostly error handling).
Error handling is very basic at this point, as we don't have a good
way of communicating errors to the guest (usually a SError).
The INT command handler is missing at this point, as we gain the
capability of actually injecting MSIs into the guest only later on.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h |   5 +-
 virt/kvm/arm/its-emul.c            | 497 ++++++++++++++++++++++++++++++++++++-
 virt/kvm/arm/its-emul.h            |  11 +
 3 files changed, 511 insertions(+), 2 deletions(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 0b450c7..80db4f6 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -253,7 +253,10 @@
  */
 #define GITS_CMD_MAPD			0x08
 #define GITS_CMD_MAPC			0x09
-#define GITS_CMD_MAPVI			0x0a
+#define GITS_CMD_MAPTI			0x0a
+/* older GIC documentation used MAPVI for this command */
+#define GITS_CMD_MAPVI			GITS_CMD_MAPTI
+#define GITS_CMD_MAPI			0x0b
 #define GITS_CMD_MOVI			0x01
 #define GITS_CMD_DISCARD		0x0f
 #define GITS_CMD_INV			0x0c
diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index 05245cb..89534c6 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -22,6 +22,7 @@
 #include <linux/kvm_host.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
+#include <linux/slab.h>
 
 #include <linux/irqchip/arm-gic-v3.h>
 #include <kvm/arm_vgic.h>
@@ -55,6 +56,34 @@ struct its_itte {
 	unsigned long *pending;
 };
 
+static struct its_device *find_its_device(struct kvm *kvm, u32 device_id)
+{
+	struct vgic_its *its = &kvm->arch.vgic.its;
+	struct its_device *device;
+
+	list_for_each_entry(device, &its->device_list, dev_list)
+		if (device_id == device->device_id)
+			return device;
+
+	return NULL;
+}
+
+static struct its_itte *find_itte(struct kvm *kvm, u32 device_id, u32 event_id)
+{
+	struct its_device *device;
+	struct its_itte *itte;
+
+	device = find_its_device(kvm, device_id);
+	if (device == NULL)
+		return NULL;
+
+	list_for_each_entry(itte, &device->itt, itte_list)
+		if (itte->event_id == event_id)
+			return itte;
+
+	return NULL;
+}
+
 #define for_each_lpi(dev, itte, kvm) \
 	list_for_each_entry(dev, &(kvm)->arch.vgic.its.device_list, dev_list) \
 		list_for_each_entry(itte, &(dev)->itt, itte_list)
@@ -71,6 +100,19 @@ static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
 	return NULL;
 }
 
+static struct its_collection *find_collection(struct kvm *kvm, int coll_id)
+{
+	struct its_collection *collection;
+
+	list_for_each_entry(collection, &kvm->arch.vgic.its.collection_list,
+			    coll_list) {
+		if (coll_id == collection->collection_id)
+			return collection;
+	}
+
+	return NULL;
+}
+
 #define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
 #define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
 
@@ -333,9 +375,461 @@ void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi)
 	spin_unlock(&its->lock);
 }
 
+static u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
+{
+	return (le64_to_cpu(its_cmd[word]) >> shift) & (BIT_ULL(size) - 1);
+}
+
+#define its_cmd_get_command(cmd)	its_cmd_mask_field(cmd, 0,  0,  8)
+#define its_cmd_get_deviceid(cmd)	its_cmd_mask_field(cmd, 0, 32, 32)
+#define its_cmd_get_id(cmd)		its_cmd_mask_field(cmd, 1,  0, 32)
+#define its_cmd_get_physical_id(cmd)	its_cmd_mask_field(cmd, 1, 32, 32)
+#define its_cmd_get_collection(cmd)	its_cmd_mask_field(cmd, 2,  0, 16)
+#define its_cmd_get_target_addr(cmd)	its_cmd_mask_field(cmd, 2, 16, 32)
+#define its_cmd_get_validbit(cmd)	its_cmd_mask_field(cmd, 2, 63,  1)
+
+/* The DISCARD command frees an Interrupt Translation Table Entry (ITTE). */
+static int vits_cmd_handle_discard(struct kvm *kvm, u64 *its_cmd)
+{
+	struct vgic_its *its = &kvm->arch.vgic.its;
+	u32 device_id;
+	u32 event_id;
+	struct its_itte *itte;
+	int ret = 0;
+
+	device_id = its_cmd_get_deviceid(its_cmd);
+	event_id = its_cmd_get_id(its_cmd);
+
+	spin_lock(&its->lock);
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte || !itte->collection) {
+		ret = E_ITS_DISCARD_UNMAPPED_INTERRUPT;
+		goto out_unlock;
+	}
+
+	__clear_bit(itte->collection->target_addr, itte->pending);
+
+	list_del(&itte->itte_list);
+	kfree(itte);
+out_unlock:
+	spin_unlock(&its->lock);
+	return ret;
+}
+
+/* The MOVI command moves an ITTE to a different collection. */
+static int vits_cmd_handle_movi(struct kvm *kvm, u64 *its_cmd)
+{
+	struct vgic_its *its = &kvm->arch.vgic.its;
+	u32 device_id = its_cmd_get_deviceid(its_cmd);
+	u32 event_id = its_cmd_get_id(its_cmd);
+	u32 coll_id = its_cmd_get_collection(its_cmd);
+	struct its_itte *itte;
+	struct its_collection *collection;
+	int ret;
+
+	spin_lock(&its->lock);
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte) {
+		ret = E_ITS_MOVI_UNMAPPED_INTERRUPT;
+		goto out_unlock;
+	}
+	if (!itte->collection) {
+		ret = E_ITS_MOVI_UNMAPPED_COLLECTION;
+		goto out_unlock;
+	}
+
+	collection = find_collection(kvm, coll_id);
+	if (!collection) {
+		ret = E_ITS_MOVI_UNMAPPED_COLLECTION;
+		goto out_unlock;
+	}
+
+	if (test_and_clear_bit(itte->collection->target_addr, itte->pending))
+		__set_bit(collection->target_addr, itte->pending);
+
+	itte->collection = collection;
+out_unlock:
+	spin_unlock(&its->lock);
+	return ret;
+}
+
+static void vits_init_collection(struct kvm *kvm,
+				 struct its_collection *collection,
+				 u32 coll_id)
+{
+	collection->collection_id = coll_id;
+
+	list_add_tail(&collection->coll_list,
+		&kvm->arch.vgic.its.collection_list);
+}
+
+/* The MAPTI and MAPI commands map LPIs to ITTEs. */
+static int vits_cmd_handle_mapi(struct kvm *kvm, u64 *its_cmd, u8 cmd)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	u32 device_id = its_cmd_get_deviceid(its_cmd);
+	u32 event_id = its_cmd_get_id(its_cmd);
+	u32 coll_id = its_cmd_get_collection(its_cmd);
+	struct its_itte *itte, *new_itte;
+	struct its_device *device;
+	struct its_collection *collection, *new_coll;
+	int lpi_nr;
+	int ret = 0;
+
+	/* Preallocate possibly needed memory here outside of the lock */
+	new_coll = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
+	new_itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
+	if (new_itte)
+		new_itte->pending = kcalloc(BITS_TO_LONGS(dist->nr_cpus),
+					    sizeof(long), GFP_KERNEL);
+
+	spin_lock(&dist->its.lock);
+
+	device = find_its_device(kvm, device_id);
+	if (!device) {
+		ret = E_ITS_MAPTI_UNMAPPED_DEVICE;
+		goto out_unlock;
+	}
+
+	collection = find_collection(kvm, coll_id);
+	if (!collection && !new_coll) {
+		ret = -ENOMEM;
+		goto out_unlock;
+	}
+
+	if (cmd == GITS_CMD_MAPTI)
+		lpi_nr = its_cmd_get_physical_id(its_cmd);
+	else
+		lpi_nr = event_id;
+	if (lpi_nr < GIC_LPI_OFFSET ||
+	    lpi_nr >= nr_idbits_propbase(dist->propbaser)) {
+		ret = E_ITS_MAPTI_PHYSICALID_OOR;
+		goto out_unlock;
+	}
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte) {
+		if (!new_itte || !new_itte->pending) {
+			ret = -ENOMEM;
+			goto out_unlock;
+		}
+		itte = new_itte;
+
+		itte->event_id	= event_id;
+		list_add_tail(&itte->itte_list, &device->itt);
+	} else {
+		if (new_itte)
+			kfree(new_itte->pending);
+		kfree(new_itte);
+	}
+
+	if (!collection) {
+		collection = new_coll;
+		vits_init_collection(kvm, collection, coll_id);
+	} else {
+		kfree(new_coll);
+	}
+
+	itte->collection = collection;
+	itte->lpi = lpi_nr;
+
+out_unlock:
+	spin_unlock(&dist->its.lock);
+	if (ret) {
+		kfree(new_coll);
+		if (new_itte)
+			kfree(new_itte->pending);
+		kfree(new_itte);
+	}
+	return ret;
+}
+
+static void vits_unmap_device(struct kvm *kvm, struct its_device *device)
+{
+	struct its_itte *itte, *temp;
+
+	/*
+	 * The spec says that unmapping a device with still valid
+	 * ITTEs associated is UNPREDICTABLE. We remove all ITTEs,
+	 * since we cannot leave the memory unreferenced.
+	 */
+	list_for_each_entry_safe(itte, temp, &device->itt, itte_list) {
+		list_del(&itte->itte_list);
+		kfree(itte);
+	}
+
+	list_del(&device->dev_list);
+	kfree(device);
+}
+
+/* The MAPD command maps device IDs to Interrupt Translation Tables (ITTs). */
+static int vits_cmd_handle_mapd(struct kvm *kvm, u64 *its_cmd)
+{
+	struct vgic_its *its = &kvm->arch.vgic.its;
+	bool valid = its_cmd_get_validbit(its_cmd);
+	u32 device_id = its_cmd_get_deviceid(its_cmd);
+	struct its_device *device, *new_device = NULL;
+
+	/* We preallocate memory outside of the lock here */
+	if (valid) {
+		new_device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
+		if (!new_device)
+			return -ENOMEM;
+	}
+
+	spin_lock(&its->lock);
+
+	device = find_its_device(kvm, device_id);
+	if (device)
+		vits_unmap_device(kvm, device);
+
+	/*
+	 * The spec does not say whether unmapping a not-mapped device
+	 * is an error, so we are done in any case.
+	 */
+	if (!valid)
+		goto out_unlock;
+
+	device = new_device;
+
+	device->device_id = device_id;
+	INIT_LIST_HEAD(&device->itt);
+
+	list_add_tail(&device->dev_list,
+		      &kvm->arch.vgic.its.device_list);
+
+out_unlock:
+	spin_unlock(&its->lock);
+	return 0;
+}
+
+/* The MAPC command maps collection IDs to redistributors. */
+static int vits_cmd_handle_mapc(struct kvm *kvm, u64 *its_cmd)
+{
+	struct vgic_its *its = &kvm->arch.vgic.its;
+	u16 coll_id;
+	u32 target_addr;
+	struct its_collection *collection, *new_coll = NULL;
+	bool valid;
+
+	valid = its_cmd_get_validbit(its_cmd);
+	coll_id = its_cmd_get_collection(its_cmd);
+	target_addr = its_cmd_get_target_addr(its_cmd);
+
+	if (target_addr >= atomic_read(&kvm->online_vcpus))
+		return E_ITS_MAPC_PROCNUM_OOR;
+
+	/* We preallocate memory outside of the lock here */
+	if (valid) {
+		new_coll = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
+		if (!new_coll)
+			return -ENOMEM;
+	}
+
+	spin_lock(&its->lock);
+	collection = find_collection(kvm, coll_id);
+
+	if (!valid) {
+		struct its_device *device;
+		struct its_itte *itte;
+		/*
+		 * Clearing the mapping for that collection ID removes the
+		 * entry from the list. If there wasn't any before, we can
+		 * go home early.
+		 */
+		if (!collection)
+			goto out_unlock;
+
+		for_each_lpi(device, itte, kvm)
+			if (itte->collection &&
+			    itte->collection->collection_id == coll_id)
+				itte->collection = NULL;
+
+		list_del(&collection->coll_list);
+		kfree(collection);
+	} else {
+		if (!collection)
+			collection = new_coll;
+		else
+			kfree(new_coll);
+
+		vits_init_collection(kvm, collection, coll_id);
+		collection->target_addr = target_addr;
+	}
+
+out_unlock:
+	spin_unlock(&its->lock);
+	return 0;
+}
+
+/* The CLEAR command removes the pending state for a particular LPI. */
+static int vits_cmd_handle_clear(struct kvm *kvm, u64 *its_cmd)
+{
+	struct vgic_its *its = &kvm->arch.vgic.its;
+	u32 device_id;
+	u32 event_id;
+	struct its_itte *itte;
+	int ret = 0;
+
+	device_id = its_cmd_get_deviceid(its_cmd);
+	event_id = its_cmd_get_id(its_cmd);
+
+	spin_lock(&its->lock);
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte) {
+		ret = E_ITS_CLEAR_UNMAPPED_INTERRUPT;
+		goto out_unlock;
+	}
+
+	if (itte->collection)
+		__clear_bit(itte->collection->target_addr, itte->pending);
+
+out_unlock:
+	spin_unlock(&its->lock);
+	return ret;
+}
+
+/* The INV command syncs the pending bit from the memory tables. */
+static int vits_cmd_handle_inv(struct kvm *kvm, u64 *its_cmd)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	u32 device_id;
+	u32 event_id;
+	struct its_itte *itte, *new_itte;
+	gpa_t propbase;
+	int ret;
+	u8 prop;
+
+	device_id = its_cmd_get_deviceid(its_cmd);
+	event_id = its_cmd_get_id(its_cmd);
+
+	spin_lock(&dist->its.lock);
+	itte = find_itte(kvm, device_id, event_id);
+	spin_unlock(&dist->its.lock);
+	if (!itte)
+		return E_ITS_INV_UNMAPPED_INTERRUPT;
+
+	/*
+	 * We cannot read from guest memory inside the spinlock, so we
+	 * need to re-read our tables to learn whether the LPI number we are
+	 * using is still valid.
+	 */
+	do {
+		propbase = BASER_BASE_ADDRESS(dist->propbaser);
+		ret = kvm_read_guest(kvm, propbase + itte->lpi - GIC_LPI_OFFSET,
+				     &prop, 1);
+		if (ret)
+			return ret;
+
+		spin_lock(&dist->its.lock);
+		new_itte = find_itte(kvm, device_id, event_id);
+		if (new_itte->lpi != itte->lpi) {
+			itte = new_itte;
+			spin_unlock(&dist->its.lock);
+			continue;
+		}
+		update_lpi_config(kvm, itte, prop);
+		spin_unlock(&dist->its.lock);
+	} while (0);
+	return 0;
+}
+
+/* The INVALL command requests flushing of all IRQ data in this collection. */
+static int vits_cmd_handle_invall(struct kvm *kvm, u64 *its_cmd)
+{
+	u32 coll_id = its_cmd_get_collection(its_cmd);
+	struct its_collection *collection;
+	struct kvm_vcpu *vcpu;
+
+	collection = find_collection(kvm, coll_id);
+	if (!collection)
+		return E_ITS_INVALL_UNMAPPED_COLLECTION;
+
+	vcpu = kvm_get_vcpu(kvm, collection->target_addr);
+
+	its_update_lpis_configuration(kvm);
+	its_sync_lpi_pending_table(vcpu);
+
+	return 0;
+}
+
+/* The MOVALL command moves all IRQs from one redistributor to another. */
+static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
+{
+	struct vgic_its *its = &kvm->arch.vgic.its;
+	u32 target1_addr = its_cmd_get_target_addr(its_cmd);
+	u32 target2_addr = its_cmd_mask_field(its_cmd, 3, 16, 32);
+	struct its_collection *collection;
+	struct its_device *device;
+	struct its_itte *itte;
+
+	if (target1_addr >= atomic_read(&kvm->online_vcpus) ||
+	    target2_addr >= atomic_read(&kvm->online_vcpus))
+		return E_ITS_MOVALL_PROCNUM_OOR;
+
+	if (target1_addr == target2_addr)
+		return 0;
+
+	spin_lock(&its->lock);
+	for_each_lpi(device, itte, kvm) {
+		/* remap all collections mapped to target address 1 */
+		collection = itte->collection;
+		if (collection && collection->target_addr == target1_addr)
+			collection->target_addr = target2_addr;
+
+		/* move pending state if LPI is affected */
+		if (test_and_clear_bit(target1_addr, itte->pending))
+			__set_bit(target2_addr, itte->pending);
+	}
+
+	spin_unlock(&its->lock);
+	return 0;
+}
+
 static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
 {
-	return -ENODEV;
+	u8 cmd = its_cmd_get_command(its_cmd);
+	int ret = -ENODEV;
+
+	switch (cmd) {
+	case GITS_CMD_MAPD:
+		ret = vits_cmd_handle_mapd(vcpu->kvm, its_cmd);
+		break;
+	case GITS_CMD_MAPC:
+		ret = vits_cmd_handle_mapc(vcpu->kvm, its_cmd);
+		break;
+	case GITS_CMD_MAPI:
+		ret = vits_cmd_handle_mapi(vcpu->kvm, its_cmd, cmd);
+		break;
+	case GITS_CMD_MAPTI:
+		ret = vits_cmd_handle_mapi(vcpu->kvm, its_cmd, cmd);
+		break;
+	case GITS_CMD_MOVI:
+		ret = vits_cmd_handle_movi(vcpu->kvm, its_cmd);
+		break;
+	case GITS_CMD_DISCARD:
+		ret = vits_cmd_handle_discard(vcpu->kvm, its_cmd);
+		break;
+	case GITS_CMD_CLEAR:
+		ret = vits_cmd_handle_clear(vcpu->kvm, its_cmd);
+		break;
+	case GITS_CMD_MOVALL:
+		ret = vits_cmd_handle_movall(vcpu->kvm, its_cmd);
+		break;
+	case GITS_CMD_INV:
+		ret = vits_cmd_handle_inv(vcpu->kvm, its_cmd);
+		break;
+	case GITS_CMD_INVALL:
+		ret = vits_cmd_handle_invall(vcpu->kvm, its_cmd);
+		break;
+	case GITS_CMD_SYNC:
+		/* we ignore this command: we are in sync all of the time */
+		ret = 0;
+		break;
+	}
+
+	return ret;
 }
 
 static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
@@ -554,6 +1048,7 @@ void vits_destroy(struct kvm *kvm)
 		list_for_each_safe(cur, temp, &dev->itt) {
 			itte = (container_of(cur, struct its_itte, itte_list));
 			list_del(cur);
+			kfree(itte->pending);
 			kfree(itte);
 		}
 		list_del(dev_cur);
diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
index cbc3877..830524a 100644
--- a/virt/kvm/arm/its-emul.h
+++ b/virt/kvm/arm/its-emul.h
@@ -39,4 +39,15 @@ void vits_destroy(struct kvm *kvm);
 bool vits_queue_lpis(struct kvm_vcpu *vcpu);
 void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int irq);
 
+#define E_ITS_MOVI_UNMAPPED_INTERRUPT		0x010107
+#define E_ITS_MOVI_UNMAPPED_COLLECTION		0x010109
+#define E_ITS_CLEAR_UNMAPPED_INTERRUPT		0x010507
+#define E_ITS_MAPC_PROCNUM_OOR			0x010902
+#define E_ITS_MAPTI_UNMAPPED_DEVICE		0x010a04
+#define E_ITS_MAPTI_PHYSICALID_OOR		0x010a06
+#define E_ITS_INV_UNMAPPED_INTERRUPT		0x010c07
+#define E_ITS_INVALL_UNMAPPED_COLLECTION	0x010d09
+#define E_ITS_MOVALL_PROCNUM_OOR		0x010e01
+#define E_ITS_DISCARD_UNMAPPED_INTERRUPT	0x010f07
+
 #endif
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (12 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 13/15] KVM: arm64: implement ITS command queue command handlers Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-07-31 13:22   ` Eric Auger
  2015-08-17 13:44   ` Eric Auger
  2015-07-10 14:21 ` [PATCH v2 15/15] KVM: arm64: enable ITS emulation as a virtual MSI controller Andre Przywara
                   ` (2 subsequent siblings)
  16 siblings, 2 replies; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

When userland wants to inject a MSI into the guest, we have to use
our data structures to find the LPI number and the VCPU to receive
the interrupt.
Use the wrapper functions to iterate the linked lists and find the
proper Interrupt Translation Table Entry. Then set the pending bit
in this ITTE to be later picked up by the LR handling code. Kick
the VCPU which is meant to handle this interrupt.
We provide a VGIC emulation model specific routine for the actual
MSI injection. The wrapper functions return an error for models not
(yet) implementing MSIs (like the GICv2 emulation).
We also provide the handler for the ITS "INT" command, which allows a
guest to trigger an MSI via the ITS command queue.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h      |  1 +
 virt/kvm/arm/its-emul.c     | 65 +++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h     |  2 ++
 virt/kvm/arm/vgic-v3-emul.c |  1 +
 4 files changed, 69 insertions(+)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 323c33a..9e1abf9 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -149,6 +149,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);
+	int	(*inject_msi)(struct kvm *, struct kvm_msi *);
 };
 
 struct vgic_io_device {
diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index 89534c6..a1c12bb 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -323,6 +323,55 @@ static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
 }
 
 /*
+ * Translates an incoming MSI request into the redistributor (=VCPU) and
+ * the associated LPI number. Sets the LPI pending bit and also marks the
+ * VCPU as having a pending interrupt.
+ */
+int vits_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct vgic_its *its = &dist->its;
+	struct its_itte *itte;
+	int cpuid;
+	bool inject = false;
+	int ret = 0;
+
+	if (!vgic_has_its(kvm))
+		return -ENODEV;
+
+	if (!(msi->flags & KVM_MSI_VALID_DEVID))
+		return -EINVAL;
+
+	spin_lock(&its->lock);
+
+	if (!its->enabled || !dist->lpis_enabled) {
+		ret = -EAGAIN;
+		goto out_unlock;
+	}
+
+	itte = find_itte(kvm, msi->devid, msi->data);
+	/* Triggering an unmapped IRQ gets silently dropped. */
+	if (!itte || !itte->collection)
+		goto out_unlock;
+
+	cpuid = itte->collection->target_addr;
+	__set_bit(cpuid, itte->pending);
+	inject = itte->enabled;
+
+out_unlock:
+	spin_unlock(&its->lock);
+
+	if (inject) {
+		spin_lock(&dist->lock);
+		__set_bit(cpuid, dist->irq_pending_on_cpu);
+		spin_unlock(&dist->lock);
+		kvm_vcpu_kick(kvm_get_vcpu(kvm, cpuid));
+	}
+
+	return ret;
+}
+
+/*
  * Find all enabled and pending LPIs and queue them into the list
  * registers.
  * The dist lock is held by the caller.
@@ -787,6 +836,19 @@ static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
 	return 0;
 }
 
+/* The INT command injects the LPI associated with that DevID/EvID pair. */
+static int vits_cmd_handle_int(struct kvm *kvm, u64 *its_cmd)
+{
+	struct kvm_msi msi = {
+		.data = its_cmd_get_id(its_cmd),
+		.devid = its_cmd_get_deviceid(its_cmd),
+		.flags = KVM_MSI_VALID_DEVID,
+	};
+
+	vits_inject_msi(kvm, &msi);
+	return 0;
+}
+
 static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
 {
 	u8 cmd = its_cmd_get_command(its_cmd);
@@ -817,6 +879,9 @@ static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
 	case GITS_CMD_MOVALL:
 		ret = vits_cmd_handle_movall(vcpu->kvm, its_cmd);
 		break;
+	case GITS_CMD_INT:
+		ret = vits_cmd_handle_int(vcpu->kvm, its_cmd);
+		break;
 	case GITS_CMD_INV:
 		ret = vits_cmd_handle_inv(vcpu->kvm, its_cmd);
 		break;
diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
index 830524a..95e56a7 100644
--- a/virt/kvm/arm/its-emul.h
+++ b/virt/kvm/arm/its-emul.h
@@ -36,6 +36,8 @@ void vgic_enable_lpis(struct kvm_vcpu *vcpu);
 int vits_init(struct kvm *kvm);
 void vits_destroy(struct kvm *kvm);
 
+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);
 
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index 4132c26..30bf7035 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -948,6 +948,7 @@ void vgic_v3_init_emulation(struct kvm *kvm)
 	dist->vm_ops.init_model = vgic_v3_init_model;
 	dist->vm_ops.destroy_model = vgic_v3_destroy_model;
 	dist->vm_ops.map_resources = vgic_v3_map_resources;
+	dist->vm_ops.inject_msi = vits_inject_msi;
 	dist->vm_ops.queue_lpis = vits_queue_lpis;
 	dist->vm_ops.unqueue_lpi = vits_unqueue_lpi;
 
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 15/15] KVM: arm64: enable ITS emulation as a virtual MSI controller
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (13 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation Andre Przywara
@ 2015-07-10 14:21 ` Andre Przywara
  2015-07-15  9:10   ` Pavel Fedin
  2015-07-15 12:02 ` [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Pavel Fedin
  2015-09-24 11:18 ` Pavel Fedin
  16 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-07-10 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

If userspace has provided a base address for the ITS register frame,
we enable the bits that advertise LPIs in the GICv3.
When the guest has enabled LPIs and the ITS, we enable the emulation
part by initializing the ITS data structures and trapping on ITS
register frame accesses by the guest.
Also we enable the KVM_SIGNAL_MSI feature to allow userland to inject
MSIs into the guest. Not having enabled the ITS emulation will lead
to a -ENODEV when trying to inject a MSI.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 Documentation/virtual/kvm/api.txt |  2 +-
 arch/arm64/kvm/Kconfig            |  1 +
 arch/arm64/kvm/reset.c            |  6 ++++++
 include/kvm/arm_vgic.h            |  6 ++++++
 virt/kvm/arm/its-emul.c           | 10 +++++++++-
 virt/kvm/arm/vgic-v3-emul.c       | 20 ++++++++++++++------
 virt/kvm/arm/vgic.c               |  8 ++++++++
 7 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index cb04095..1b53155 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2134,7 +2134,7 @@ after pausing the vcpu, but before it is resumed.
 4.71 KVM_SIGNAL_MSI
 
 Capability: KVM_CAP_SIGNAL_MSI
-Architectures: x86
+Architectures: x86 arm64
 Type: vm ioctl
 Parameters: struct kvm_msi (in)
 Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index bfffe8f..ff9722f 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -31,6 +31,7 @@ config KVM
 	select KVM_VFIO
 	select HAVE_KVM_EVENTFD
 	select HAVE_KVM_IRQFD
+	select HAVE_KVM_MSI
 	---help---
 	  Support hosting virtualized guest machines.
 
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 866502b..aff209e 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -64,6 +64,12 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_EL1_32BIT:
 		r = cpu_has_32bit_el1();
 		break;
+	case KVM_CAP_MSI_DEVID:
+		if (!kvm)
+			r = -EINVAL;
+		else
+			r = kvm->arch.vgic.msis_require_devid;
+		break;
 	default:
 		r = 0;
 	}
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 9e1abf9..f50081c 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -162,6 +162,7 @@ struct vgic_io_device {
 
 struct vgic_its {
 	bool			enabled;
+	struct vgic_io_device	iodev;
 	spinlock_t		lock;
 	u64			cbaser;
 	int			creadr;
@@ -180,6 +181,9 @@ struct vgic_dist {
 	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
 	u32			vgic_model;
 
+	/* Do injected MSIs require an additional device ID? */
+	bool			msis_require_devid;
+
 	int			nr_cpus;
 	int			nr_irqs;
 
@@ -371,4 +375,6 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
 }
 #endif
 
+int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
+
 #endif
diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index a1c12bb..b6caefd 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -1073,6 +1073,7 @@ int vits_init(struct kvm *kvm)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
 	struct vgic_its *its = &dist->its;
+	int ret;
 
 	dist->pendbaser = kmalloc(sizeof(u64) * dist->nr_cpus, GFP_KERNEL);
 	if (!dist->pendbaser)
@@ -1087,9 +1088,16 @@ int vits_init(struct kvm *kvm)
 	INIT_LIST_HEAD(&its->device_list);
 	INIT_LIST_HEAD(&its->collection_list);
 
+	ret = vgic_register_kvm_io_dev(kvm, dist->vgic_its_base,
+				       KVM_VGIC_V3_ITS_SIZE, vgicv3_its_ranges,
+				       -1, &its->iodev);
+	if (ret)
+		return ret;
+
 	its->enabled = false;
+	dist->msis_require_devid = true;
 
-	return -ENXIO;
+	return 0;
 }
 
 void vits_destroy(struct kvm *kvm)
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index 30bf7035..9fd1238 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -8,7 +8,6 @@
  *
  * Limitations of the emulation:
  * (RAZ/WI: read as zero, write ignore, RAO/WI: read as one, write ignore)
- * - We do not support LPIs (yet). TYPER.LPIS is reported as 0 and is RAZ/WI.
  * - We do not support the message based interrupts (MBIs) triggered by
  *   writes to the GICD_{SET,CLR}SPI_* registers. TYPER.MBIS is reported as 0.
  * - We do not support the (optional) backwards compatibility feature.
@@ -87,10 +86,10 @@ static bool handle_mmio_ctlr(struct kvm_vcpu *vcpu,
 /*
  * As this implementation does not provide compatibility
  * with GICv2 (ARE==1), we report zero CPUs in bits [5..7].
- * Also LPIs and MBIs are not supported, so we set the respective bits to 0.
- * Also we report at most 2**10=1024 interrupt IDs (to match 1024 SPIs).
+ * Also we report at most 2**10=1024 interrupt IDs (to match 1024 SPIs)
+ * and provide 16 bits worth of LPI number space (to give 8192 LPIs).
  */
-#define INTERRUPT_ID_BITS 10
+#define INTERRUPT_ID_BITS_SPIS 10
 static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
 			      struct kvm_exit_mmio *mmio, phys_addr_t offset)
 {
@@ -98,7 +97,12 @@ static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
 
 	reg = (min(vcpu->kvm->arch.vgic.nr_irqs, 1024) >> 5) - 1;
 
-	reg |= (INTERRUPT_ID_BITS - 1) << 19;
+	if (vgic_has_its(vcpu->kvm)) {
+		reg |= GICD_TYPER_LPIS;
+		reg |= (INTERRUPT_ID_BITS_ITS - 1) << 19;
+	} else {
+		reg |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+	}
 
 	vgic_reg_access(mmio, &reg, offset,
 			ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
@@ -543,7 +547,9 @@ static bool handle_mmio_ctlr_redist(struct kvm_vcpu *vcpu,
 	vgic_reg_access(mmio, &reg, offset,
 			ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
 	if (!dist->lpis_enabled && (reg & GICR_CTLR_ENABLE_LPIS)) {
-		/* Eventually do something */
+		vgic_enable_lpis(vcpu);
+		dist->lpis_enabled = true;
+		return true;
 	}
 	return false;
 }
@@ -570,6 +576,8 @@ static bool handle_mmio_typer_redist(struct kvm_vcpu *vcpu,
 	reg = redist_vcpu->vcpu_id << 8;
 	if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
 		reg |= GICR_TYPER_LAST;
+	if (vgic_has_its(vcpu->kvm))
+		reg |= GICR_TYPER_PLPIS;
 	vgic_reg_access(mmio, &reg, offset,
 			ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
 	return false;
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 9dfd094..081a1ef 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -2246,3 +2246,11 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
 {
 	return 0;
 }
+
+int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
+{
+	if (kvm->arch.vgic.vm_ops.inject_msi)
+		return kvm->arch.vgic.vm_ops.inject_msi(kvm, msi);
+	else
+		return -ENODEV;
+}
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 15/15] KVM: arm64: enable ITS emulation as a virtual MSI controller
  2015-07-10 14:21 ` [PATCH v2 15/15] KVM: arm64: enable ITS emulation as a virtual MSI controller Andre Przywara
@ 2015-07-15  9:10   ` Pavel Fedin
  2015-07-15  9:52     ` Andre Przywara
  0 siblings, 1 reply; 69+ messages in thread
From: Pavel Fedin @ 2015-07-15  9:10 UTC (permalink / raw)
  To: linux-arm-kernel



Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia


> -----Original Message-----
> From: kvm-owner at vger.kernel.org [mailto:kvm-owner at vger.kernel.org] On Behalf Of Andre Przywara
> Sent: Friday, July 10, 2015 5:22 PM
> To: marc.zyngier at arm.com; christoffer.dall at linaro.org; kvmarm at lists.cs.columbia.edu
> Cc: eric.auger at linaro.org; Pavel Fedin; linux-arm-kernel at lists.infradead.org; kvm at vger.kernel.org
> Subject: [PATCH v2 15/15] KVM: arm64: enable ITS emulation as a virtual MSI controller
> 
> If userspace has provided a base address for the ITS register frame,
> we enable the bits that advertise LPIs in the GICv3.
> When the guest has enabled LPIs and the ITS, we enable the emulation
> part by initializing the ITS data structures and trapping on ITS
> register frame accesses by the guest.
> Also we enable the KVM_SIGNAL_MSI feature to allow userland to inject
> MSIs into the guest. Not having enabled the ITS emulation will lead
> to a -ENODEV when trying to inject a MSI.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  Documentation/virtual/kvm/api.txt |  2 +-
>  arch/arm64/kvm/Kconfig            |  1 +
>  arch/arm64/kvm/reset.c            |  6 ++++++
>  include/kvm/arm_vgic.h            |  6 ++++++
>  virt/kvm/arm/its-emul.c           | 10 +++++++++-
>  virt/kvm/arm/vgic-v3-emul.c       | 20 ++++++++++++++------
>  virt/kvm/arm/vgic.c               |  8 ++++++++
>  7 files changed, 45 insertions(+), 8 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index cb04095..1b53155 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2134,7 +2134,7 @@ after pausing the vcpu, but before it is resumed.
>  4.71 KVM_SIGNAL_MSI
> 
>  Capability: KVM_CAP_SIGNAL_MSI
> -Architectures: x86
> +Architectures: x86 arm64
>  Type: vm ioctl
>  Parameters: struct kvm_msi (in)
>  Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error
> diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
> index bfffe8f..ff9722f 100644
> --- a/arch/arm64/kvm/Kconfig
> +++ b/arch/arm64/kvm/Kconfig
> @@ -31,6 +31,7 @@ config KVM
>  	select KVM_VFIO
>  	select HAVE_KVM_EVENTFD
>  	select HAVE_KVM_IRQFD
> +	select HAVE_KVM_MSI
>  	---help---
>  	  Support hosting virtualized guest machines.
> 
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index 866502b..aff209e 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -64,6 +64,12 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
>  	case KVM_CAP_ARM_EL1_32BIT:
>  		r = cpu_has_32bit_el1();
>  		break;
> +	case KVM_CAP_MSI_DEVID:
> +		if (!kvm)
> +			r = -EINVAL;
> +		else
> +			r = kvm->arch.vgic.msis_require_devid;
> +		break;
>  	default:
>  		r = 0;
>  	}

 This can be very inconvenient to use IMHO. The problem here is that capability is set to TRUE only
after everything has been instantiated, and the VM is about to run. And, for example, qemu first
queries for capabilities, then creates models. May be we should just set the capability to TRUE for
ARM architecture in general, and make GICv2m MSIs simply ignoring this flag and device ID?
 Of course, we can explicitly check for the capability after vGICv3 + ITS instantiation, however in
this case it IMHO simply loses sense, because since we are using ITS, we already know for sure that
device IDs are required, because ITS requires them by design.

> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 9e1abf9..f50081c 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -162,6 +162,7 @@ struct vgic_io_device {
> 
>  struct vgic_its {
>  	bool			enabled;
> +	struct vgic_io_device	iodev;
>  	spinlock_t		lock;
>  	u64			cbaser;
>  	int			creadr;
> @@ -180,6 +181,9 @@ struct vgic_dist {
>  	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>  	u32			vgic_model;
> 
> +	/* Do injected MSIs require an additional device ID? */
> +	bool			msis_require_devid;
> +
>  	int			nr_cpus;
>  	int			nr_irqs;
> 
> @@ -371,4 +375,6 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>  }
>  #endif
> 
> +int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
> +
>  #endif
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index a1c12bb..b6caefd 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -1073,6 +1073,7 @@ int vits_init(struct kvm *kvm)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
>  	struct vgic_its *its = &dist->its;
> +	int ret;
> 
>  	dist->pendbaser = kmalloc(sizeof(u64) * dist->nr_cpus, GFP_KERNEL);
>  	if (!dist->pendbaser)
> @@ -1087,9 +1088,16 @@ int vits_init(struct kvm *kvm)
>  	INIT_LIST_HEAD(&its->device_list);
>  	INIT_LIST_HEAD(&its->collection_list);
> 
> +	ret = vgic_register_kvm_io_dev(kvm, dist->vgic_its_base,
> +				       KVM_VGIC_V3_ITS_SIZE, vgicv3_its_ranges,
> +				       -1, &its->iodev);
> +	if (ret)
> +		return ret;
> +
>  	its->enabled = false;
> +	dist->msis_require_devid = true;
> 
> -	return -ENXIO;
> +	return 0;
>  }
> 
>  void vits_destroy(struct kvm *kvm)
> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
> index 30bf7035..9fd1238 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -8,7 +8,6 @@
>   *
>   * Limitations of the emulation:
>   * (RAZ/WI: read as zero, write ignore, RAO/WI: read as one, write ignore)
> - * - We do not support LPIs (yet). TYPER.LPIS is reported as 0 and is RAZ/WI.
>   * - We do not support the message based interrupts (MBIs) triggered by
>   *   writes to the GICD_{SET,CLR}SPI_* registers. TYPER.MBIS is reported as 0.
>   * - We do not support the (optional) backwards compatibility feature.
> @@ -87,10 +86,10 @@ static bool handle_mmio_ctlr(struct kvm_vcpu *vcpu,
>  /*
>   * As this implementation does not provide compatibility
>   * with GICv2 (ARE==1), we report zero CPUs in bits [5..7].
> - * Also LPIs and MBIs are not supported, so we set the respective bits to 0.
> - * Also we report at most 2**10=1024 interrupt IDs (to match 1024 SPIs).
> + * Also we report at most 2**10=1024 interrupt IDs (to match 1024 SPIs)
> + * and provide 16 bits worth of LPI number space (to give 8192 LPIs).
>   */
> -#define INTERRUPT_ID_BITS 10
> +#define INTERRUPT_ID_BITS_SPIS 10
>  static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
>  			      struct kvm_exit_mmio *mmio, phys_addr_t offset)
>  {
> @@ -98,7 +97,12 @@ static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
> 
>  	reg = (min(vcpu->kvm->arch.vgic.nr_irqs, 1024) >> 5) - 1;
> 
> -	reg |= (INTERRUPT_ID_BITS - 1) << 19;
> +	if (vgic_has_its(vcpu->kvm)) {
> +		reg |= GICD_TYPER_LPIS;
> +		reg |= (INTERRUPT_ID_BITS_ITS - 1) << 19;
> +	} else {
> +		reg |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
> +	}
> 
>  	vgic_reg_access(mmio, &reg, offset,
>  			ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
> @@ -543,7 +547,9 @@ static bool handle_mmio_ctlr_redist(struct kvm_vcpu *vcpu,
>  	vgic_reg_access(mmio, &reg, offset,
>  			ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
>  	if (!dist->lpis_enabled && (reg & GICR_CTLR_ENABLE_LPIS)) {
> -		/* Eventually do something */
> +		vgic_enable_lpis(vcpu);
> +		dist->lpis_enabled = true;
> +		return true;
>  	}
>  	return false;
>  }
> @@ -570,6 +576,8 @@ static bool handle_mmio_typer_redist(struct kvm_vcpu *vcpu,
>  	reg = redist_vcpu->vcpu_id << 8;
>  	if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
>  		reg |= GICR_TYPER_LAST;
> +	if (vgic_has_its(vcpu->kvm))
> +		reg |= GICR_TYPER_PLPIS;
>  	vgic_reg_access(mmio, &reg, offset,
>  			ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
>  	return false;
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index 9dfd094..081a1ef 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -2246,3 +2246,11 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
>  {
>  	return 0;
>  }
> +
> +int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
> +{
> +	if (kvm->arch.vgic.vm_ops.inject_msi)
> +		return kvm->arch.vgic.vm_ops.inject_msi(kvm, msi);
> +	else
> +		return -ENODEV;
> +}
> --
> 2.3.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 15/15] KVM: arm64: enable ITS emulation as a virtual MSI controller
  2015-07-15  9:10   ` Pavel Fedin
@ 2015-07-15  9:52     ` Andre Przywara
  2015-07-15 10:01       ` Pavel Fedin
  0 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-07-15  9:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/07/15 10:10, Pavel Fedin wrote:
>> -----Original Message-----
>> From: kvm-owner at vger.kernel.org [mailto:kvm-owner at vger.kernel.org] On Behalf Of Andre Przywara
>> Sent: Friday, July 10, 2015 5:22 PM
>> To: marc.zyngier at arm.com; christoffer.dall at linaro.org; kvmarm at lists.cs.columbia.edu
>> Cc: eric.auger at linaro.org; Pavel Fedin; linux-arm-kernel at lists.infradead.org; kvm at vger.kernel.org
>> Subject: [PATCH v2 15/15] KVM: arm64: enable ITS emulation as a virtual MSI controller
>>
>> If userspace has provided a base address for the ITS register frame,
>> we enable the bits that advertise LPIs in the GICv3.
>> When the guest has enabled LPIs and the ITS, we enable the emulation
>> part by initializing the ITS data structures and trapping on ITS
>> register frame accesses by the guest.
>> Also we enable the KVM_SIGNAL_MSI feature to allow userland to inject
>> MSIs into the guest. Not having enabled the ITS emulation will lead
>> to a -ENODEV when trying to inject a MSI.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  Documentation/virtual/kvm/api.txt |  2 +-
>>  arch/arm64/kvm/Kconfig            |  1 +
>>  arch/arm64/kvm/reset.c            |  6 ++++++
>>  include/kvm/arm_vgic.h            |  6 ++++++
>>  virt/kvm/arm/its-emul.c           | 10 +++++++++-
>>  virt/kvm/arm/vgic-v3-emul.c       | 20 ++++++++++++++------
>>  virt/kvm/arm/vgic.c               |  8 ++++++++
>>  7 files changed, 45 insertions(+), 8 deletions(-)
>>
>> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
>> index cb04095..1b53155 100644
>> --- a/Documentation/virtual/kvm/api.txt
>> +++ b/Documentation/virtual/kvm/api.txt
>> @@ -2134,7 +2134,7 @@ after pausing the vcpu, but before it is resumed.
>>  4.71 KVM_SIGNAL_MSI
>>
>>  Capability: KVM_CAP_SIGNAL_MSI
>> -Architectures: x86
>> +Architectures: x86 arm64
>>  Type: vm ioctl
>>  Parameters: struct kvm_msi (in)
>>  Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error
>> diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
>> index bfffe8f..ff9722f 100644
>> --- a/arch/arm64/kvm/Kconfig
>> +++ b/arch/arm64/kvm/Kconfig
>> @@ -31,6 +31,7 @@ config KVM
>>  	select KVM_VFIO
>>  	select HAVE_KVM_EVENTFD
>>  	select HAVE_KVM_IRQFD
>> +	select HAVE_KVM_MSI
>>  	---help---
>>  	  Support hosting virtualized guest machines.
>>
>> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
>> index 866502b..aff209e 100644
>> --- a/arch/arm64/kvm/reset.c
>> +++ b/arch/arm64/kvm/reset.c
>> @@ -64,6 +64,12 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
>>  	case KVM_CAP_ARM_EL1_32BIT:
>>  		r = cpu_has_32bit_el1();
>>  		break;
>> +	case KVM_CAP_MSI_DEVID:
>> +		if (!kvm)
>> +			r = -EINVAL;
>> +		else
>> +			r = kvm->arch.vgic.msis_require_devid;
>> +		break;
>>  	default:
>>  		r = 0;
>>  	}
> 
>  This can be very inconvenient to use IMHO. The problem here is that capability is set to TRUE only
> after everything has been instantiated, and the VM is about to run. And, for example, qemu first
> queries for capabilities, then creates models.

But why would it need the capability to create models? The idea is to
check the capability before the actual KVM_SIGNAL_MSI or
KVM_SET_GSI_ROUTING ioctl (and cache that result). I have a function
with a static variable to do that, so it looks like:

+  if (check_for_msi_devid(kvm)) {
+    irq_routing->entries[irq_routing->nr].flags = KVM_MSI_VALID_DEVID;
+    irq_routing->entries[irq_routing->nr].u.msi.devid = device_id;
+  }

> May be we should just set the capability to TRUE for
> ARM architecture in general, and make GICv2m MSIs simply ignoring this flag and device ID?

Possibly, but it would be saner to tell userland that it's a per VM
decision for ARM. Since you need extra support bits in the userland
anyway (to set up GICv2M or ITS emulation), I think it is acceptable to
require a late, per-VM capability check in userland in that case.

>  Of course, we can explicitly check for the capability after vGICv3 + ITS instantiation, however in
> this case it IMHO simply loses sense, because since we are using ITS, we already know for sure that
> device IDs are required, because ITS requires them by design.

Yeah, that is true to some degree.
But the idea is that the userland code that sets up GSI routing or
triggers MSIs via KVM_SIGNAL_MSI is architecture agnostic (or it could
be), so you don't want to introduce #ifdef ARM in there.
But for the rest of the code I agree there is no real need to
differentiate between requiring a device ID or not. Reworking Eric's and
my patches proved that - at least on the kernel side: propagating the
device ID unconditionally does not harm even if the value in there is
garbage. Also there is no real choice - either you require the device ID
(ITS emulation) or you ignore it (GICv2M and other archs).

Cheers,
Andre.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 15/15] KVM: arm64: enable ITS emulation as a virtual MSI controller
  2015-07-15  9:52     ` Andre Przywara
@ 2015-07-15 10:01       ` Pavel Fedin
  0 siblings, 0 replies; 69+ messages in thread
From: Pavel Fedin @ 2015-07-15 10:01 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello!

> But why would it need the capability to create models?

 Actually it doesn't.

> The idea is to
> check the capability before the actual KVM_SIGNAL_MSI or
> KVM_SET_GSI_ROUTING ioctl (and cache that result). I have a function
> with a static variable to do that, so it looks like:
> 
> +  if (check_for_msi_devid(kvm)) {
> +    irq_routing->entries[irq_routing->nr].flags = KVM_MSI_VALID_DEVID;
> +    irq_routing->entries[irq_routing->nr].u.msi.devid = device_id;
> +  }
> 
> > May be we should just set the capability to TRUE for
> > ARM architecture in general, and make GICv2m MSIs simply ignoring this flag and device ID?
> 
> Possibly, but it would be saner to tell userland that it's a per VM
> decision for ARM. Since you need extra support bits in the userland
> anyway (to set up GICv2M or ITS emulation), I think it is acceptable to
> require a late, per-VM capability check in userland in that case.

 Well, agree, and formally this is more correct. Just it would require slightly more additions to
qemu. But it's not a real problem.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (14 preceding siblings ...)
  2015-07-10 14:21 ` [PATCH v2 15/15] KVM: arm64: enable ITS emulation as a virtual MSI controller Andre Przywara
@ 2015-07-15 12:02 ` Pavel Fedin
  2015-09-24 11:18 ` Pavel Fedin
  16 siblings, 0 replies; 69+ messages in thread
From: Pavel Fedin @ 2015-07-15 12:02 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello!

> this respin tries to address all comments I got so far from the list.
> Thanks to Eric, Pavel and Christoffer for the review!

 Tested-by: Pavel Fedin <p.fedin@samsung.com>

 Works fine.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation
  2015-07-10 14:21 ` [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation Andre Przywara
@ 2015-07-31 13:22   ` Eric Auger
  2015-08-02 20:20     ` Andre Przywara
  2015-08-17 13:44   ` Eric Auger
  1 sibling, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-07-31 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andre,
On 07/10/2015 04:21 PM, Andre Przywara wrote:
> When userland wants to inject a MSI into the guest, we have to use
> our data structures to find the LPI number and the VCPU to receive
> the interrupt.
> Use the wrapper functions to iterate the linked lists and find the
> proper Interrupt Translation Table Entry. Then set the pending bit
> in this ITTE to be later picked up by the LR handling code. Kick
> the VCPU which is meant to handle this interrupt.
> We provide a VGIC emulation model specific routine for the actual
> MSI injection. The wrapper functions return an error for models not
> (yet) implementing MSIs (like the GICv2 emulation).
> We also provide the handler for the ITS "INT" command, which allows a
> guest to trigger an MSI via the ITS command queue.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h      |  1 +
>  virt/kvm/arm/its-emul.c     | 65 +++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h     |  2 ++
>  virt/kvm/arm/vgic-v3-emul.c |  1 +
>  4 files changed, 69 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 323c33a..9e1abf9 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -149,6 +149,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);
> +	int	(*inject_msi)(struct kvm *, struct kvm_msi *);
>  };
>  
>  struct vgic_io_device {
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index 89534c6..a1c12bb 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -323,6 +323,55 @@ static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
>  }
>  
>  /*
> + * Translates an incoming MSI request into the redistributor (=VCPU) and
> + * the associated LPI number. Sets the LPI pending bit and also marks the
> + * VCPU as having a pending interrupt.
> + */
> +int vits_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct vgic_its *its = &dist->its;
> +	struct its_itte *itte;
> +	int cpuid;
> +	bool inject = false;
> +	int ret = 0;
> +
> +	if (!vgic_has_its(kvm))
> +		return -ENODEV;
> +
> +	if (!(msi->flags & KVM_MSI_VALID_DEVID))
> +		return -EINVAL;
I am currently reworking the GSI routing series according to latest
comments (flag usage on userside and removal of EXTENDED_MSI type on
kernel side as you suggested). Given the data path,

kvm_send_userspace_msi (kvm_msi*)
|_ kvm_set_msi (kvm_kernel_irq_routing_entry *)
	|_ kvm->arch.vgic.vm_ops.inject_msi (kvm_msi *)

the above check is useless I think since in kvm_set_msi I need to
populate a kvm_msi struct from a kernel routing entry struct. The kernel
routing entry struct has no info about the validity of devid so I
systematically sets the flag in kvm_msi.

I am still dubious about not storing the KVM_MSI_VALID_DEVID info
somewhere in the kernel routing entry struct.

Best Regards

Eric


> +
> +	spin_lock(&its->lock);
> +
> +	if (!its->enabled || !dist->lpis_enabled) {
> +		ret = -EAGAIN;
> +		goto out_unlock;
> +	}
> +
> +	itte = find_itte(kvm, msi->devid, msi->data);
> +	/* Triggering an unmapped IRQ gets silently dropped. */
> +	if (!itte || !itte->collection)
> +		goto out_unlock;
> +
> +	cpuid = itte->collection->target_addr;
> +	__set_bit(cpuid, itte->pending);
> +	inject = itte->enabled;
> +
> +out_unlock:
> +	spin_unlock(&its->lock);
> +
> +	if (inject) {
> +		spin_lock(&dist->lock);
> +		__set_bit(cpuid, dist->irq_pending_on_cpu);
> +		spin_unlock(&dist->lock);
> +		kvm_vcpu_kick(kvm_get_vcpu(kvm, cpuid));
> +	}
> +
> +	return ret;
> +}
> +
> +/*
>   * Find all enabled and pending LPIs and queue them into the list
>   * registers.
>   * The dist lock is held by the caller.
> @@ -787,6 +836,19 @@ static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
>  	return 0;
>  }
>  
> +/* The INT command injects the LPI associated with that DevID/EvID pair. */
> +static int vits_cmd_handle_int(struct kvm *kvm, u64 *its_cmd)
> +{
> +	struct kvm_msi msi = {
> +		.data = its_cmd_get_id(its_cmd),
> +		.devid = its_cmd_get_deviceid(its_cmd),
> +		.flags = KVM_MSI_VALID_DEVID,
> +	};
> +
> +	vits_inject_msi(kvm, &msi);
> +	return 0;
> +}
> +
>  static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
>  {
>  	u8 cmd = its_cmd_get_command(its_cmd);
> @@ -817,6 +879,9 @@ static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
>  	case GITS_CMD_MOVALL:
>  		ret = vits_cmd_handle_movall(vcpu->kvm, its_cmd);
>  		break;
> +	case GITS_CMD_INT:
> +		ret = vits_cmd_handle_int(vcpu->kvm, its_cmd);
> +		break;
>  	case GITS_CMD_INV:
>  		ret = vits_cmd_handle_inv(vcpu->kvm, its_cmd);
>  		break;
> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
> index 830524a..95e56a7 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -36,6 +36,8 @@ void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>  int vits_init(struct kvm *kvm);
>  void vits_destroy(struct kvm *kvm);
>  
> +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);
>  
> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
> index 4132c26..30bf7035 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -948,6 +948,7 @@ void vgic_v3_init_emulation(struct kvm *kvm)
>  	dist->vm_ops.init_model = vgic_v3_init_model;
>  	dist->vm_ops.destroy_model = vgic_v3_destroy_model;
>  	dist->vm_ops.map_resources = vgic_v3_map_resources;
> +	dist->vm_ops.inject_msi = vits_inject_msi;
>  	dist->vm_ops.queue_lpis = vits_queue_lpis;
>  	dist->vm_ops.unqueue_lpi = vits_unqueue_lpi;
>  
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation
  2015-07-31 13:22   ` Eric Auger
@ 2015-08-02 20:20     ` Andre Przywara
  2015-08-03  6:41       ` Pavel Fedin
  0 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-08-02 20:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 31/07/15 14:22, Eric Auger wrote:

Salut Eric,

> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>> When userland wants to inject a MSI into the guest, we have to use
>> our data structures to find the LPI number and the VCPU to receive
>> the interrupt.
>> Use the wrapper functions to iterate the linked lists and find the
>> proper Interrupt Translation Table Entry. Then set the pending bit
>> in this ITTE to be later picked up by the LR handling code. Kick
>> the VCPU which is meant to handle this interrupt.
>> We provide a VGIC emulation model specific routine for the actual
>> MSI injection. The wrapper functions return an error for models not
>> (yet) implementing MSIs (like the GICv2 emulation).
>> We also provide the handler for the ITS "INT" command, which allows a
>> guest to trigger an MSI via the ITS command queue.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/arm_vgic.h      |  1 +
>>  virt/kvm/arm/its-emul.c     | 65 +++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/its-emul.h     |  2 ++
>>  virt/kvm/arm/vgic-v3-emul.c |  1 +
>>  4 files changed, 69 insertions(+)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 323c33a..9e1abf9 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -149,6 +149,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);
>> +	int	(*inject_msi)(struct kvm *, struct kvm_msi *);
>>  };
>>  
>>  struct vgic_io_device {
>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>> index 89534c6..a1c12bb 100644
>> --- a/virt/kvm/arm/its-emul.c
>> +++ b/virt/kvm/arm/its-emul.c
>> @@ -323,6 +323,55 @@ static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
>>  }
>>  
>>  /*
>> + * Translates an incoming MSI request into the redistributor (=VCPU) and
>> + * the associated LPI number. Sets the LPI pending bit and also marks the
>> + * VCPU as having a pending interrupt.
>> + */
>> +int vits_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +	struct vgic_its *its = &dist->its;
>> +	struct its_itte *itte;
>> +	int cpuid;
>> +	bool inject = false;
>> +	int ret = 0;
>> +
>> +	if (!vgic_has_its(kvm))
>> +		return -ENODEV;
>> +
>> +	if (!(msi->flags & KVM_MSI_VALID_DEVID))
>> +		return -EINVAL;
> I am currently reworking the GSI routing series according to latest
> comments (flag usage on userside and removal of EXTENDED_MSI type on
> kernel side as you suggested). Given the data path,
> 
> kvm_send_userspace_msi (kvm_msi*)
> |_ kvm_set_msi (kvm_kernel_irq_routing_entry *)
> 	|_ kvm->arch.vgic.vm_ops.inject_msi (kvm_msi *)
> 
> the above check is useless I think since in kvm_set_msi I need to
> populate a kvm_msi struct from a kernel routing entry struct. The kernel
> routing entry struct has no info about the validity of devid so I
> systematically sets the flag in kvm_msi.
> 
> I am still dubious about not storing the KVM_MSI_VALID_DEVID info
> somewhere in the kernel routing entry struct.

When I reworked our code to only use a flag and not a separate routing
type I ended up with the flag only guarding assignments, which wouldn't
hurt if done unconditionally (since they are all u32's). So the whole
usage of the flag is somewhat in jeopardy now.
Either the eventual MSI consumer requires a DevID (ITS emulation, which
will not work without it) or the consumer does not care at all and can
totally ignore it (GICv2m). So I think we can always pass on the DevID
field and let the final function decide whether to use it or not. But
somehow this doesn't sound right to me, so maybe I am missing something
here?

Cheers,
Andre.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation
  2015-08-02 20:20     ` Andre Przywara
@ 2015-08-03  6:41       ` Pavel Fedin
  2015-08-03  9:07         ` Eric Auger
  0 siblings, 1 reply; 69+ messages in thread
From: Pavel Fedin @ 2015-08-03  6:41 UTC (permalink / raw)
  To: linux-arm-kernel

 Hi!

> When I reworked our code to only use a flag and not a separate routing
> type I ended up with the flag only guarding assignments, which wouldn't
> hurt if done unconditionally (since they are all u32's). So the whole
> usage of the flag is somewhat in jeopardy now.
> Either the eventual MSI consumer requires a DevID (ITS emulation, which
> will not work without it) or the consumer does not care at all and can
> totally ignore it (GICv2m). So I think we can always pass on the DevID

 I have just checked my current code, and you know what... You are right. We already have a per-VM
capability which actually tells us that MSIs for this VM require devID. Therefore, we really don't
need this flag at all, neither for MSI doorbell, nor for GSI routing.
 All we need is 'devid' field, which indeed can be just ignored for GICv2(m), just for simplicity.
Ignoring would happen automatically, because IIRC older kernels do not explicitly check 'pad' for
being zero, do they? And indeed in this case the userland can supply devid unconditionally, making
things even simpler.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation
  2015-08-03  6:41       ` Pavel Fedin
@ 2015-08-03  9:07         ` Eric Auger
  2015-08-03  9:16           ` Pavel Fedin
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-03  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andre, Pavel,
On 08/03/2015 08:41 AM, Pavel Fedin wrote:
>  Hi!
> 
>> When I reworked our code to only use a flag and not a separate routing
>> type I ended up with the flag only guarding assignments, which wouldn't
>> hurt if done unconditionally (since they are all u32's). So the whole
>> usage of the flag is somewhat in jeopardy now.
>> Either the eventual MSI consumer requires a DevID (ITS emulation, which
>> will not work without it) or the consumer does not care at all and can
>> totally ignore it (GICv2m). So I think we can always pass on the DevID
> 
>  I have just checked my current code, and you know what... You are right. We already have a per-VM
> capability which actually tells us that MSIs for this VM require devID. Therefore, we really don't
> need this flag at all, neither for MSI doorbell, nor for GSI routing.
>  All we need is 'devid' field, which indeed can be just ignored for GICv2(m), just for simplicity.
> Ignoring would happen automatically, because IIRC older kernels do not explicitly check 'pad' for
> being zero, do they? And indeed in this case the userland can supply devid unconditionally, making
> things even simpler.

Again the case that leaves me uncomfortable is the one where the
userspace does not provide the devid whereas it must (GICv3 ITS case).
We cannot be confident in userspace to behave correctly. In such a case
devid == 0 and we cannot discriminate this from a valid devid. Do I miss
something?

Best Regards

Eric
> 
> Kind regards,
> Pavel Fedin
> Expert Engineer
> Samsung Electronics Research center Russia
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation
  2015-08-03  9:07         ` Eric Auger
@ 2015-08-03  9:16           ` Pavel Fedin
  2015-08-03 15:37             ` Eric Auger
  0 siblings, 1 reply; 69+ messages in thread
From: Pavel Fedin @ 2015-08-03  9:16 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello!

> Again the case that leaves me uncomfortable is the one where the
> userspace does not provide the devid whereas it must (GICv3 ITS case).

 Hypothetical broken userland which does not exist for now ?
 IMHO the userland should just know, that if it supports ITS, it has to provide devIDs.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation
  2015-08-03  9:16           ` Pavel Fedin
@ 2015-08-03 15:37             ` Eric Auger
  2015-08-03 17:06               ` Marc Zyngier
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-03 15:37 UTC (permalink / raw)
  To: linux-arm-kernel

Andre, Pavel,
On 08/03/2015 11:16 AM, Pavel Fedin wrote:
>  Hello!
> 
>> Again the case that leaves me uncomfortable is the one where the
>> userspace does not provide the devid whereas it must (GICv3 ITS case).
> 
>  Hypothetical broken userland which does not exist for now ?
Yes but that's the rule to be not confident in *any* userspace, isn't it?

As of now I prefer keeping the flags at uapi level and propagate it
downto the kernel, as long as I don't have any answer for the unset
devid discrimination question. Please apologize for my stubbornness ;-)

Best Regards

Eric


>  IMHO the userland should just know, that if it supports ITS, it has to provide devIDs.
> 
> Kind regards,
> Pavel Fedin
> Expert Engineer
> Samsung Electronics Research center Russia
> 
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation
  2015-08-03 15:37             ` Eric Auger
@ 2015-08-03 17:06               ` Marc Zyngier
  2015-08-04  6:53                 ` Pavel Fedin
  2015-08-24 14:14                 ` Andre Przywara
  0 siblings, 2 replies; 69+ messages in thread
From: Marc Zyngier @ 2015-08-03 17:06 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/08/15 16:37, Eric Auger wrote:
> Andre, Pavel,
> On 08/03/2015 11:16 AM, Pavel Fedin wrote:
>>  Hello!
>>
>>> Again the case that leaves me uncomfortable is the one where the
>>> userspace does not provide the devid whereas it must (GICv3 ITS case).
>>
>>  Hypothetical broken userland which does not exist for now ?
> Yes but that's the rule to be not confident in *any* userspace, isn't it?
> 
> As of now I prefer keeping the flags at uapi level and propagate it
> downto the kernel, as long as I don't have any answer for the unset
> devid discrimination question. Please apologize for my stubbornness ;-)

I think this flag should be kept, as it really indicates what is valid
in the MSI structure. It also has other benefits such as making obvious
what userspace expects, which can then be checked against the kernel's
own expectations.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation
  2015-08-03 17:06               ` Marc Zyngier
@ 2015-08-04  6:53                 ` Pavel Fedin
  2015-08-24 14:14                 ` Andre Przywara
  1 sibling, 0 replies; 69+ messages in thread
From: Pavel Fedin @ 2015-08-04  6:53 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello!

> I think this flag should be kept, as it really indicates what is valid
> in the MSI structure. It also has other benefits such as making obvious
> what userspace expects, which can then be checked against the kernel's
> own expectations.

 I'm OK with the flag despite it's indeed a small bit redundant. But i see that kernel's policy is
to have insurance against all possible and impossible bad inputs, and the flag really fits into the
concept.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-07-10 14:21 ` [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor Andre Przywara
@ 2015-08-12  9:01   ` Eric Auger
  2015-08-24 16:33     ` Andre Przywara
  2015-10-02  9:55   ` Pavel Fedin
  1 sibling, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-12  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andre,
On 07/10/2015 04:21 PM, Andre Przywara wrote:
> Currently we track which IRQ has been mapped to which VGIC list
> register and also have to synchronize both. We used to do this
> to hold some extra state (for instance the active bit).
> It turns out that this extra state in the LRs is no longer needed and
> this extra tracking causes some pain later.
> Remove the tracking feature (lr_map and lr_used) and get rid of
> quite some code on the way.
> On a guest exit we pick up all still pending IRQs from the LRs and put
> them back in the distributor. We don't care about active-only IRQs,
> so we keep them in the LRs. They will be retired either by our
> vgic_process_maintenance() routine or by the GIC hardware in case of
> edge triggered interrupts.
> In places where we scan LRs we now use our shadow copy of the ELRSR
> register directly.
> This code change means we lose the "piggy-back" optimization, which
> would re-use an active-only LR to inject the pending state on top of
> it. Tracing with various workloads shows that this actually occurred
> very rarely, the ballpark figure is about once every 10,000 exits
> in a disk I/O heavy workload. Also the list registers don't seem to
> as scarce as assumed, with all 4 LRs on the popular implementations
> used less than once every 100,000 exits.
> 
> This has been briefly tested on Midway, Juno and the model (the latter
> both with GICv2 and GICv3 guests).
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h |   6 ---
>  virt/kvm/arm/vgic-v2.c |   1 +
>  virt/kvm/arm/vgic-v3.c |   1 +
>  virt/kvm/arm/vgic.c    | 143 ++++++++++++++++++++++---------------------------
>  4 files changed, 66 insertions(+), 85 deletions(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 133ea00..2ccfa9a 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -279,9 +279,6 @@ struct vgic_v3_cpu_if {
>  };
>  
>  struct vgic_cpu {
> -	/* per IRQ to LR mapping */
> -	u8		*vgic_irq_lr_map;
> -
>  	/* Pending/active/both interrupts on this VCPU */
>  	DECLARE_BITMAP(	pending_percpu, VGIC_NR_PRIVATE_IRQS);
>  	DECLARE_BITMAP(	active_percpu, VGIC_NR_PRIVATE_IRQS);
> @@ -292,9 +289,6 @@ struct vgic_cpu {
>  	unsigned long   *active_shared;
>  	unsigned long   *pend_act_shared;
>  
> -	/* Bitmap of used/free list registers */
> -	DECLARE_BITMAP(	lr_used, VGIC_V2_MAX_LRS);
> -
>  	/* Number of list registers on this CPU */
>  	int		nr_lr;
>  
> diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c
> index f9b9c7c..f723710 100644
> --- a/virt/kvm/arm/vgic-v2.c
> +++ b/virt/kvm/arm/vgic-v2.c
> @@ -144,6 +144,7 @@ static void vgic_v2_enable(struct kvm_vcpu *vcpu)
>  	 * anyway.
>  	 */
>  	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = 0;
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr = ~0;
>  
>  	/* Get the show on the road... */
>  	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
> diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
> index dff0602..21e5d28 100644
> --- a/virt/kvm/arm/vgic-v3.c
> +++ b/virt/kvm/arm/vgic-v3.c
> @@ -178,6 +178,7 @@ static void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  	 * anyway.
>  	 */
>  	vgic_v3->vgic_vmcr = 0;
> +	vgic_v3->vgic_elrsr = ~0;
>  
>  	/*
>  	 * If we are emulating a GICv3, we do it in an non-GICv2-compatible
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index bc40137..394622c 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -79,7 +79,6 @@
>  #include "vgic.h"
>  
>  static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu);
> -static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu);
>  static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr);
>  static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr, struct vgic_lr lr_desc);
>  
> @@ -647,6 +646,17 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
>  	return false;
>  }
>  
> +static void vgic_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
> +			       struct vgic_lr vlr)
> +{
> +	vgic_ops->sync_lr_elrsr(vcpu, lr, vlr);
> +}
why not renaming this into vgic_set_elrsr. This would be homogeneous
with other virtual interface control register setters?
> +
> +static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
> +{
> +	return vgic_ops->get_elrsr(vcpu);
> +}
If I am not wrong, each time you manipulate the elrsr you handle the
bitmap. why not directly returning an unsigned long * then (elrsr_ptr)?
> +
>  /**
>   * vgic_unqueue_irqs - move pending/active IRQs from LRs to the distributor
>   * @vgic_cpu: Pointer to the vgic_cpu struct holding the LRs
> @@ -658,9 +668,11 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
>  void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
>  {
>  	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	u64 elrsr = vgic_get_elrsr(vcpu);
> +	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
>  	int i;
>  
> -	for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) {
> +	for_each_clear_bit(i, elrsr_ptr, vgic_cpu->nr_lr) {
>  		struct vgic_lr lr = vgic_get_lr(vcpu, i);
>  
>  		/*
> @@ -703,7 +715,7 @@ void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
>  		 * Mark the LR as free for other use.
>  		 */
>  		BUG_ON(lr.state & LR_STATE_MASK);
> -		vgic_retire_lr(i, lr.irq, vcpu);
> +		vgic_sync_lr_elrsr(vcpu, i, lr);
>  		vgic_irq_clear_queued(vcpu, lr.irq);
>  
>  		/* Finally update the VGIC state. */
> @@ -1011,17 +1023,6 @@ static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr,
>  	vgic_ops->set_lr(vcpu, lr, vlr);
>  }
>  
> -static void vgic_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
> -			       struct vgic_lr vlr)
> -{
> -	vgic_ops->sync_lr_elrsr(vcpu, lr, vlr);
> -}
> -
> -static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
> -{
> -	return vgic_ops->get_elrsr(vcpu);
> -}
> -
>  static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
>  {
>  	return vgic_ops->get_eisr(vcpu);
> @@ -1062,18 +1063,6 @@ static inline void vgic_enable(struct kvm_vcpu *vcpu)
>  	vgic_ops->enable(vcpu);
>  }
>  
> -static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
> -{
> -	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> -	struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr);
> -
> -	vlr.state = 0;
> -	vgic_set_lr(vcpu, lr_nr, vlr);
> -	clear_bit(lr_nr, vgic_cpu->lr_used);
> -	vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
> -	vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
> -}
> -
>  /*
>   * An interrupt may have been disabled after being made pending on the
>   * CPU interface (the classic case is a timer running while we're
> @@ -1085,23 +1074,32 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
>   */
>  static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
>  {
> -	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	u64 elrsr = vgic_get_elrsr(vcpu);
> +	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
if you agree with above modif I would simply rename elrsr_ptr into elrsr.
>  	int lr;
> +	struct vgic_lr vlr;
why moving this declaration here. I think this can remain in the block.
>  
> -	for_each_set_bit(lr, vgic_cpu->lr_used, vgic->nr_lr) {
> -		struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
> +	for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) {
> +		vlr = vgic_get_lr(vcpu, lr);
>  
>  		if (!vgic_irq_is_enabled(vcpu, vlr.irq)) {
> -			vgic_retire_lr(lr, vlr.irq, vcpu);
> -			if (vgic_irq_is_queued(vcpu, vlr.irq))
> -				vgic_irq_clear_queued(vcpu, vlr.irq);
> +			vlr.state = 0;
> +			vgic_set_lr(vcpu, lr, vlr);
> +			vgic_sync_lr_elrsr(vcpu, lr, vlr);
vgic_set_elrsr?

the "if (vgic_irq_is_queued(vcpu, vlr.irq))" check disappeared. This
change might be introduced separately.
> +			vgic_irq_clear_queued(vcpu, vlr.irq);
>  		}
>  	}
>  }
>  
>  static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
> -				 int lr_nr, struct vgic_lr vlr)
I don't think this change of proto is compatible with Marc's "KVM:
arm/arm64: vgic: Allow HW interrupts to be queued to a guest".
I think we need to keep former signature.
> +				 int lr_nr, int sgi_source_id)
>  {
> +	struct vgic_lr vlr;
> +
> +	vlr.state = 0;
> +	vlr.irq = irq;
> +	vlr.source = sgi_source_id;
> +
>  	if (vgic_irq_is_active(vcpu, irq)) {
>  		vlr.state |= LR_STATE_ACTIVE;
>  		kvm_debug("Set active, clear distributor: 0x%x\n", vlr.state);
> @@ -1126,9 +1124,9 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>   */
>  bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>  {
> -	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>  	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> -	struct vgic_lr vlr;
> +	u64 elrsr = vgic_get_elrsr(vcpu);
> +	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
>  	int lr;
>  
>  	/* Sanitize the input... */
> @@ -1138,42 +1136,20 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>  
>  	kvm_debug("Queue IRQ%d\n", irq);
>  
> -	lr = vgic_cpu->vgic_irq_lr_map[irq];
> -
> -	/* Do we have an active interrupt for the same CPUID? */
> -	if (lr != LR_EMPTY) {
> -		vlr = vgic_get_lr(vcpu, lr);
> -		if (vlr.source == sgi_source_id) {
> -			kvm_debug("LR%d piggyback for IRQ%d\n", lr, vlr.irq);
> -			BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
> -			vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
> -			return true;
> -		}
> -	}
> +	lr = find_first_bit(elrsr_ptr, vgic->nr_lr);
>  
> -	/* Try to use another LR for this interrupt */
> -	lr = find_first_zero_bit((unsigned long *)vgic_cpu->lr_used,
> -			       vgic->nr_lr);
>  	if (lr >= vgic->nr_lr)
>  		return false;
>  
>  	kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id);
> -	vgic_cpu->vgic_irq_lr_map[irq] = lr;
> -	set_bit(lr, vgic_cpu->lr_used);
>  
> -	vlr.irq = irq;
> -	vlr.source = sgi_source_id;
> -	vlr.state = 0;
> -	vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
> +	vgic_queue_irq_to_lr(vcpu, irq, lr, sgi_source_id);
>  
>  	return true;
>  }
>  
>  static bool vgic_queue_hwirq(struct kvm_vcpu *vcpu, int irq)
>  {
> -	if (!vgic_can_sample_irq(vcpu, irq))
> -		return true; /* level interrupt, already queued */
> -
I think that change needs to be introduced in a separate patch as the
other one mentioned above and justified since it affects the state machine.

Best Regards

Eric
>  	if (vgic_queue_irq(vcpu, 0, irq)) {
>  		if (vgic_irq_is_edge(vcpu, irq)) {
>  			vgic_dist_irq_clear_pending(vcpu, irq);
> @@ -1346,29 +1322,44 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>  	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>  	u64 elrsr;
>  	unsigned long *elrsr_ptr;
> -	int lr, pending;
> -	bool level_pending;
> +	struct vgic_lr vlr;
> +	int lr_nr;
> +	bool pending;
> +
> +	pending = vgic_process_maintenance(vcpu);
>  
> -	level_pending = vgic_process_maintenance(vcpu);
>  	elrsr = vgic_get_elrsr(vcpu);
>  	elrsr_ptr = u64_to_bitmask(&elrsr);
>  
> -	/* Clear mappings for empty LRs */
> -	for_each_set_bit(lr, elrsr_ptr, vgic->nr_lr) {
> -		struct vgic_lr vlr;
> +	for_each_clear_bit(lr_nr, elrsr_ptr, vgic_cpu->nr_lr) {
> +		vlr = vgic_get_lr(vcpu, lr_nr);
> +
> +		BUG_ON(!(vlr.state & LR_STATE_MASK));
> +		pending = true;
>  
> -		if (!test_and_clear_bit(lr, vgic_cpu->lr_used))
> +		/* Reestablish SGI source for pending and active SGIs */
> +		if (vlr.irq < VGIC_NR_SGIS)
> +			add_sgi_source(vcpu, vlr.irq, vlr.source);
> +
> +		/*
> +		 * If the LR holds a pure active (10) interrupt then keep it
> +		 * in the LR without mirroring this status in the emulation.
> +		 */
> +		if (vlr.state == LR_STATE_ACTIVE)
>  			continue;
>  
> -		vlr = vgic_get_lr(vcpu, lr);
> +		if (vlr.state & LR_STATE_PENDING)
> +			vgic_dist_irq_set_pending(vcpu, vlr.irq);
>  
> -		BUG_ON(vlr.irq >= dist->nr_irqs);
> -		vgic_cpu->vgic_irq_lr_map[vlr.irq] = LR_EMPTY;
> +		/* Mark this LR as empty now. */
> +		vlr.state = 0;
> +		vgic_set_lr(vcpu, lr_nr, vlr);
> +		vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
>  	}
> +	vgic_update_state(vcpu->kvm);
>  
> -	/* Check if we still have something up our sleeve... */
> -	pending = find_first_zero_bit(elrsr_ptr, vgic->nr_lr);
> -	if (level_pending || pending < vgic->nr_lr)
> +	/* vgic_update_state would not cover only-active IRQs */
> +	if (pending)
>  		set_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu);
>  }
>  
> @@ -1590,11 +1581,9 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
>  	kfree(vgic_cpu->pending_shared);
>  	kfree(vgic_cpu->active_shared);
>  	kfree(vgic_cpu->pend_act_shared);
> -	kfree(vgic_cpu->vgic_irq_lr_map);
>  	vgic_cpu->pending_shared = NULL;
>  	vgic_cpu->active_shared = NULL;
>  	vgic_cpu->pend_act_shared = NULL;
> -	vgic_cpu->vgic_irq_lr_map = NULL;
>  }
>  
>  static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
> @@ -1605,18 +1594,14 @@ static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
>  	vgic_cpu->pending_shared = kzalloc(sz, GFP_KERNEL);
>  	vgic_cpu->active_shared = kzalloc(sz, GFP_KERNEL);
>  	vgic_cpu->pend_act_shared = kzalloc(sz, GFP_KERNEL);
> -	vgic_cpu->vgic_irq_lr_map = kmalloc(nr_irqs, GFP_KERNEL);
>  
>  	if (!vgic_cpu->pending_shared
>  		|| !vgic_cpu->active_shared
> -		|| !vgic_cpu->pend_act_shared
> -		|| !vgic_cpu->vgic_irq_lr_map) {
> +		|| !vgic_cpu->pend_act_shared) {
>  		kvm_vgic_vcpu_destroy(vcpu);
>  		return -ENOMEM;
>  	}
>  
> -	memset(vgic_cpu->vgic_irq_lr_map, LR_EMPTY, nr_irqs);
> -
>  	/*
>  	 * Store the number of LRs per vcpu, so we don't have to go
>  	 * all the way to the distributor structure to find out. Only
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 04/15] KVM: arm/arm64: extend arch CAP checks to allow per-VM capabilities
  2015-07-10 14:21 ` [PATCH v2 04/15] KVM: arm/arm64: extend arch CAP checks to allow per-VM capabilities Andre Przywara
@ 2015-08-12 12:26   ` Eric Auger
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Auger @ 2015-08-12 12:26 UTC (permalink / raw)
  To: linux-arm-kernel

Reviewed-by: Eric Auger <eric.auger@linaro.org>

Best Regards

Eric

On 07/10/2015 04:21 PM, Andre Przywara wrote:
> KVM capabilities can be a per-VM property, though ARM/ARM64 currently
> does not pass on the VM pointer to the architecture specific
> capability handlers.
> Add a "struct kvm*" parameter to those function to later allow proper
> per-VM capability reporting.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  arch/arm/include/asm/kvm_host.h   | 2 +-
>  arch/arm/kvm/arm.c                | 2 +-
>  arch/arm64/include/asm/kvm_host.h | 2 +-
>  arch/arm64/kvm/reset.c            | 2 +-
>  4 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index e896d2c..56cac05 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -213,7 +213,7 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
>  	kvm_call_hyp((void*)hyp_stack_ptr, vector_ptr, pgd_ptr);
>  }
>  
> -static inline int kvm_arch_dev_ioctl_check_extension(long ext)
> +static inline int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
>  {
>  	return 0;
>  }
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index bc738d2..7c65353 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -196,7 +196,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  		r = KVM_MAX_VCPUS;
>  		break;
>  	default:
> -		r = kvm_arch_dev_ioctl_check_extension(ext);
> +		r = kvm_arch_dev_ioctl_check_extension(kvm, ext);
>  		break;
>  	}
>  	return r;
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 2709db2..8d78a72 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -47,7 +47,7 @@
>  
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> -int kvm_arch_dev_ioctl_check_extension(long ext);
> +int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext);
>  
>  struct kvm_arch {
>  	/* The VMID generation used for the virt. memory system */
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index 0b43265..866502b 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -56,7 +56,7 @@ static bool cpu_has_32bit_el1(void)
>  	return !!(pfr0 & 0x20);
>  }
>  
> -int kvm_arch_dev_ioctl_check_extension(long ext)
> +int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
>  {
>  	int r;
>  
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 05/15] KVM: arm/arm64: make GIC frame address initialization model specific
  2015-07-10 14:21 ` [PATCH v2 05/15] KVM: arm/arm64: make GIC frame address initialization model specific Andre Przywara
@ 2015-08-12 13:02   ` Eric Auger
  2015-08-24 17:24     ` Andre Przywara
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-12 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/10/2015 04:21 PM, Andre Przywara wrote:
> Currently we initialize all the possible GIC frame addresses in one
> function, without looking at the specific GIC model we instantiate
> for the guest.
> As this gets confusing when adding another VGIC model later, lets
> move these initializations into the respective model's init 
nit: tobe more precise the init emulation function (not the
vgic_v2/v3_init_model model's init function). pfouh?! ;-)
functions.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic-v2-emul.c | 3 +++
>  virt/kvm/arm/vgic-v3-emul.c | 3 +++
>  virt/kvm/arm/vgic.c         | 3 ---
>  3 files changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c
> index 1390797..8faa28c 100644
> --- a/virt/kvm/arm/vgic-v2-emul.c
> +++ b/virt/kvm/arm/vgic-v2-emul.c
> @@ -567,6 +567,9 @@ void vgic_v2_init_emulation(struct kvm *kvm)
>  	dist->vm_ops.init_model = vgic_v2_init_model;
>  	dist->vm_ops.map_resources = vgic_v2_map_resources;
>  
> +	dist->vgic_cpu_base = VGIC_ADDR_UNDEF;
> +	dist->vgic_dist_base = VGIC_ADDR_UNDEF;
Looks strange to see the common dist_base here. Why don't you leave it
in common part, kvm_vgic_create; all the more so you left
kvm->arch.vgic.vctrl_base = vgic->vctrl_base in kvm_vgic_create.

Eric
> +
>  	kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
>  }
>  
> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
> index d2eeb20..1f42348 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -885,6 +885,9 @@ void vgic_v3_init_emulation(struct kvm *kvm)
>  	dist->vm_ops.destroy_model = vgic_v3_destroy_model;
>  	dist->vm_ops.map_resources = vgic_v3_map_resources;
>  
> +	dist->vgic_dist_base = VGIC_ADDR_UNDEF;
> +	dist->vgic_redist_base = VGIC_ADDR_UNDEF;
> +
>  	kvm->arch.max_vcpus = KVM_MAX_VCPUS;
>  }
>  
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index cc8f5ed..59f1801 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -1830,9 +1830,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
>  	kvm->arch.vgic.in_kernel = true;
>  	kvm->arch.vgic.vgic_model = type;
>  	kvm->arch.vgic.vctrl_base = vgic->vctrl_base;
> -	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
> -	kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
> -	kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
>  
>  out_unlock:
>  	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 07/15] KVM: arm64: handle ITS related GICv3 redistributor registers
  2015-07-10 14:21 ` [PATCH v2 07/15] KVM: arm64: handle ITS related GICv3 redistributor registers Andre Przywara
@ 2015-08-13 12:17   ` Eric Auger
  2015-08-24 18:08     ` Andre Przywara
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-13 12:17 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/10/2015 04:21 PM, Andre Przywara wrote:
> In the GICv3 redistributor there are the PENDBASER and PROPBASER
> registers which we did not emulate so far, as they only make sense
> when having an ITS. In preparation for that emulate those MMIO
> accesses by storing the 64-bit data written into it into a variable
> which we later read in the ITS emulation.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h      |  8 ++++++++
>  virt/kvm/arm/vgic-v3-emul.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic.c         | 35 +++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic.h         |  4 ++++
>  4 files changed, 91 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 3ee063b..8c6cb0e 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -256,6 +256,14 @@ struct vgic_dist {
>  	struct vgic_vm_ops	vm_ops;
>  	struct vgic_io_device	dist_iodev;
>  	struct vgic_io_device	*redist_iodevs;
> +
> +	/* Address of LPI configuration table shared by all redistributors */
> +	u64			propbaser;
> +
> +	/* Addresses of LPI pending tables per redistributor */
> +	u64			*pendbaser;
> +
> +	bool			lpis_enabled;
>  };
>  
>  struct vgic_v2_cpu_if {
> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
> index a8cf669..5269ad1 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -651,6 +651,38 @@ static bool handle_mmio_cfg_reg_redist(struct kvm_vcpu *vcpu,
>  	return vgic_handle_cfg_reg(reg, mmio, offset);
>  }
>  
> +/* We don't trigger any actions here, just store the register value */
> +static bool handle_mmio_propbaser_redist(struct kvm_vcpu *vcpu,
> +					 struct kvm_exit_mmio *mmio,
> +					 phys_addr_t offset)
> +{
> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +	int mode = ACCESS_READ_VALUE;
> +
> +	/* Storing a value with LPIs already enabled is undefined */
> +	mode |= dist->lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
> +	vgic_handle_base_register(vcpu, mmio, offset, &dist->propbaser, mode);
> +
> +	return false;
> +}
> +
> +/* We don't trigger any actions here, just store the register value */
> +static bool handle_mmio_pendbaser_redist(struct kvm_vcpu *vcpu,
> +					 struct kvm_exit_mmio *mmio,
> +					 phys_addr_t offset)
> +{
> +	struct kvm_vcpu *rdvcpu = mmio->private;
> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +	int mode = ACCESS_READ_VALUE;
> +
> +	/* Storing a value with LPIs already enabled is undefined */
> +	mode |= dist->lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
> +	vgic_handle_base_register(vcpu, mmio, offset,
> +				  &dist->pendbaser[rdvcpu->vcpu_id], mode);
> +
> +	return false;
> +}
> +
>  #define SGI_base(x) ((x) + SZ_64K)
>  
>  static const struct vgic_io_range vgic_redist_ranges[] = {
> @@ -679,6 +711,18 @@ static const struct vgic_io_range vgic_redist_ranges[] = {
>  		.handle_mmio    = handle_mmio_raz_wi,
>  	},
>  	{
> +		.base		= GICR_PENDBASER,
> +		.len		= 0x08,
> +		.bits_per_irq	= 0,
> +		.handle_mmio	= handle_mmio_pendbaser_redist,
> +	},
> +	{
> +		.base		= GICR_PROPBASER,
> +		.len		= 0x08,
> +		.bits_per_irq	= 0,
> +		.handle_mmio	= handle_mmio_propbaser_redist,
> +	},
> +	{
>  		.base           = GICR_IDREGS,
>  		.len            = 0x30,
>  		.bits_per_irq   = 0,
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index 15e447f..49ee92b 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -446,6 +446,41 @@ void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
>  	}
>  }
>  
> +/* handle a 64-bit register access */
> +void vgic_handle_base_register(struct kvm_vcpu *vcpu,
> +			       struct kvm_exit_mmio *mmio,
> +			       phys_addr_t offset, u64 *basereg,
> +			       int mode)
> +{
why do we have vcpu in the proto? I don't see it used. Also if it were
can't we fetch it from mmio->private?

why not renaming this into something like vgic_reg64_access as par
vgic_reg_access 32b flavor above. vgic_handle* usually is the name of
the region handler returning bool?


> +	u32 reg;
> +	u64 breg;
> +
> +	switch (offset & ~3) {
> +	case 0x00:
> +		breg = *basereg;
> +		reg = lower_32_bits(breg);
> +		vgic_reg_access(mmio, &reg, offset & 3, mode);
> +		if (mmio->is_write && (mode & ACCESS_WRITE_VALUE)) {
> +			breg &= GENMASK_ULL(63, 32);
> +			breg |= reg;
> +			*basereg = breg;
> +		}
> +		break;
> +	case 0x04:
> +		breg = *basereg;
> +		reg = upper_32_bits(breg);
> +		vgic_reg_access(mmio, &reg, offset & 3, mode);
> +		if (mmio->is_write && (mode & ACCESS_WRITE_VALUE)) {
> +			breg  = lower_32_bits(breg);
> +			breg |= (u64)reg << 32;
> +			*basereg = breg;
> +		}
> +		break;
> +	}
> +}
> +
> +
> +
some spare white lines

Best Regards

Eric
>  bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
>  			phys_addr_t offset)
>  {
> diff --git a/virt/kvm/arm/vgic.h b/virt/kvm/arm/vgic.h
> index a093f5c..b2d791c 100644
> --- a/virt/kvm/arm/vgic.h
> +++ b/virt/kvm/arm/vgic.h
> @@ -71,6 +71,10 @@ void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
>  		     phys_addr_t offset, int mode);
>  bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
>  			phys_addr_t offset);
> +void vgic_handle_base_register(struct kvm_vcpu *vcpu,
> +			       struct kvm_exit_mmio *mmio,
> +			       phys_addr_t offset, u64 *basereg,
> +			       int mode);
>  
>  static inline
>  u32 mmio_data_read(struct kvm_exit_mmio *mmio, u32 mask)
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 06/15] KVM: arm64: Introduce new MMIO region for the ITS base address
  2015-07-10 14:21 ` [PATCH v2 06/15] KVM: arm64: Introduce new MMIO region for the ITS base address Andre Przywara
@ 2015-08-13 12:17   ` Eric Auger
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Auger @ 2015-08-13 12:17 UTC (permalink / raw)
  To: linux-arm-kernel

Reviewed-by: Eric Auger <eric.auger@linaro.org>

On 07/10/2015 04:21 PM, Andre Przywara wrote:
> The ARM GICv3 ITS controller requires a separate register frame to
> cover ITS specific registers. Add a new VGIC address type and store
> the address in a field in the vgic_dist structure.
> Provide a function to check whether userland has provided the address,
> so ITS functionality can be guarded by that check.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  Documentation/virtual/kvm/devices/arm-vgic.txt |  9 +++++++++
>  arch/arm64/include/uapi/asm/kvm.h              |  2 ++
>  include/kvm/arm_vgic.h                         |  3 +++
>  virt/kvm/arm/vgic-v3-emul.c                    |  2 ++
>  virt/kvm/arm/vgic.c                            | 16 ++++++++++++++++
>  virt/kvm/arm/vgic.h                            |  1 +
>  6 files changed, 33 insertions(+)
> 
> diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
> index 3fb9054..ec715f9e 100644
> --- a/Documentation/virtual/kvm/devices/arm-vgic.txt
> +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt
> @@ -39,6 +39,15 @@ Groups:
>        Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
>        This address needs to be 64K aligned.
>  
> +    KVM_VGIC_V3_ADDR_TYPE_ITS (rw, 64-bit)
> +      Base address in the guest physical address space of the GICv3 ITS
> +      control register frame. The ITS allows MSI(-X) interrupts to be
> +      injected into guests. This extension is optional, if the kernel
> +      does not support the ITS, the call returns -ENODEV.
> +      This memory is solely for the guest to access the ITS control
> +      registers and does not cover the ITS translation register.
> +      Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
> +      This address needs to be 64K aligned and the region covers 64 KByte.
>  
>    KVM_DEV_ARM_VGIC_GRP_DIST_REGS
>    Attributes:
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index d268320..a89b407c 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -81,9 +81,11 @@ struct kvm_regs {
>  /* Supported VGICv3 address types  */
>  #define KVM_VGIC_V3_ADDR_TYPE_DIST	2
>  #define KVM_VGIC_V3_ADDR_TYPE_REDIST	3
> +#define KVM_VGIC_V3_ADDR_TYPE_ITS	4
>  
>  #define KVM_VGIC_V3_DIST_SIZE		SZ_64K
>  #define KVM_VGIC_V3_REDIST_SIZE		(2 * SZ_64K)
> +#define KVM_VGIC_V3_ITS_SIZE		SZ_64K
>  
>  #define KVM_ARM_VCPU_POWER_OFF		0 /* CPU is started in OFF state */
>  #define KVM_ARM_VCPU_EL1_32BIT		1 /* CPU running a 32bit VM */
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index b18e2c5..3ee063b 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -178,6 +178,9 @@ struct vgic_dist {
>  		phys_addr_t		vgic_redist_base;
>  	};
>  
> +	/* The base address of the ITS control register frame */
> +	phys_addr_t		vgic_its_base;
> +
>  	/* Distributor enabled */
>  	u32			enabled;
>  
> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
> index 1f42348..a8cf669 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -887,6 +887,7 @@ void vgic_v3_init_emulation(struct kvm *kvm)
>  
>  	dist->vgic_dist_base = VGIC_ADDR_UNDEF;
>  	dist->vgic_redist_base = VGIC_ADDR_UNDEF;
> +	dist->vgic_its_base = VGIC_ADDR_UNDEF;
>  
>  	kvm->arch.max_vcpus = KVM_MAX_VCPUS;
>  }
> @@ -1059,6 +1060,7 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  			return -ENXIO;
>  		case KVM_VGIC_V3_ADDR_TYPE_DIST:
>  		case KVM_VGIC_V3_ADDR_TYPE_REDIST:
> +		case KVM_VGIC_V3_ADDR_TYPE_ITS:
>  			return 0;
>  		}
>  		break;
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index 59f1801..15e447f 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -930,6 +930,16 @@ int vgic_register_kvm_io_dev(struct kvm *kvm, gpa_t base, int len,
>  	return ret;
>  }
>  
> +bool vgic_has_its(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +
> +	if (dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
> +		return false;
> +
> +	return !IS_VGIC_ADDR_UNDEF(dist->vgic_its_base);
> +}
> +
>  static int vgic_nr_shared_irqs(struct vgic_dist *dist)
>  {
>  	return dist->nr_irqs - VGIC_NR_PRIVATE_IRQS;
> @@ -1927,6 +1937,12 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
>  		block_size = KVM_VGIC_V3_REDIST_SIZE;
>  		alignment = SZ_64K;
>  		break;
> +	case KVM_VGIC_V3_ADDR_TYPE_ITS:
> +		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
> +		addr_ptr = &vgic->vgic_its_base;
> +		block_size = KVM_VGIC_V3_ITS_SIZE;
> +		alignment = SZ_64K;
> +		break;
>  #endif
>  	default:
>  		r = -ENODEV;
> diff --git a/virt/kvm/arm/vgic.h b/virt/kvm/arm/vgic.h
> index 0df74cb..a093f5c 100644
> --- a/virt/kvm/arm/vgic.h
> +++ b/virt/kvm/arm/vgic.h
> @@ -136,5 +136,6 @@ int vgic_get_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr);
>  int vgic_init(struct kvm *kvm);
>  void vgic_v2_init_emulation(struct kvm *kvm);
>  void vgic_v3_init_emulation(struct kvm *kvm);
> +bool vgic_has_its(struct kvm *kvm);
>  
>  #endif
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 08/15] KVM: arm64: introduce ITS emulation file with stub functions
  2015-07-10 14:21 ` [PATCH v2 08/15] KVM: arm64: introduce ITS emulation file with stub functions Andre Przywara
@ 2015-08-13 12:48   ` Eric Auger
  2015-08-25  9:39     ` Andre Przywara
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-13 12:48 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/10/2015 04:21 PM, Andre Przywara wrote:
> The ARM GICv3 ITS emulation code goes into a separate file, but
> needs to be connected to the GICv3 emulation, of which it is an
> option.
> Introduce the skeleton with function stubs to be filled later.
> Introduce the basic ITS data structure and initialize it, but don't
> return any success yet, as we are not yet ready for the show.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  arch/arm64/kvm/Makefile            |   1 +
>  include/kvm/arm_vgic.h             |   6 ++
>  include/linux/irqchip/arm-gic-v3.h |   1 +
>  virt/kvm/arm/its-emul.c            | 125 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h            |  35 +++++++++++
>  virt/kvm/arm/vgic-v3-emul.c        |  24 ++++++-
>  6 files changed, 189 insertions(+), 3 deletions(-)
>  create mode 100644 virt/kvm/arm/its-emul.c
>  create mode 100644 virt/kvm/arm/its-emul.h
> 
> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
> index f90f4aa..9803307 100644
> --- a/arch/arm64/kvm/Makefile
> +++ b/arch/arm64/kvm/Makefile
> @@ -25,5 +25,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v2-switch.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/its-emul.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v3-switch.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 8c6cb0e..9e9d4aa 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -156,6 +156,11 @@ struct vgic_io_device {
>  	struct kvm_io_device dev;
>  };
>  
> +struct vgic_its {
> +	bool			enabled;
> +	spinlock_t		lock;
> +};
> +
>  struct vgic_dist {
>  	spinlock_t		lock;
>  	bool			in_kernel;
> @@ -264,6 +269,7 @@ struct vgic_dist {
>  	u64			*pendbaser;
>  
>  	bool			lpis_enabled;
> +	struct vgic_its		its;
>  };
>  
>  struct vgic_v2_cpu_if {
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index ffbc034..df4e527 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -177,6 +177,7 @@
>  #define GITS_CWRITER			0x0088
>  #define GITS_CREADR			0x0090
>  #define GITS_BASER			0x0100
> +#define GITS_IDREGS_BASE		0xffd0
>  #define GITS_PIDR2			GICR_PIDR2
>  
>  #define GITS_TRANSLATER			0x10040
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> new file mode 100644
> index 0000000..659dd39
> --- /dev/null
> +++ b/virt/kvm/arm/its-emul.c
> @@ -0,0 +1,125 @@
> +/*
> + * GICv3 ITS emulation
> + *
> + * Copyright (C) 2015 ARM Ltd.
> + * Author: Andre Przywara <andre.przywara@arm.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/cpu.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <linux/interrupt.h>
> +
> +#include <linux/irqchip/arm-gic-v3.h>
> +#include <kvm/arm_vgic.h>
> +
> +#include <asm/kvm_emulate.h>
> +#include <asm/kvm_arm.h>
> +#include <asm/kvm_mmu.h>
> +
> +#include "vgic.h"
> +#include "its-emul.h"
> +
> +static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
> +				  struct kvm_exit_mmio *mmio,
> +				  phys_addr_t offset)
> +{
> +	return false;
> +}
> +
> +static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
> +				    struct kvm_exit_mmio *mmio,
> +				    phys_addr_t offset)
> +{
> +	return false;
> +}
> +
> +static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
> +				    struct kvm_exit_mmio *mmio,
> +				    phys_addr_t offset)
> +{
> +	return false;
> +}
> +
> +static bool handle_mmio_gits_cwriter(struct kvm_vcpu *vcpu,
> +				     struct kvm_exit_mmio *mmio,
> +				     phys_addr_t offset)
> +{
> +	return false;
> +}
> +
> +static bool handle_mmio_gits_creadr(struct kvm_vcpu *vcpu,
> +				    struct kvm_exit_mmio *mmio,
> +				    phys_addr_t offset)
> +{
> +	return false;
> +}
> +
> +static const struct vgic_io_range vgicv3_its_ranges[] = {
> +	{
> +		.base		= GITS_CTLR,
> +		.len		= 0x10,
> +		.bits_per_irq	= 0,
> +		.handle_mmio	= handle_mmio_misc_gits,
> +	},
> +	{
> +		.base		= GITS_CBASER,
> +		.len		= 0x08,
> +		.bits_per_irq	= 0,
> +		.handle_mmio	= handle_mmio_gits_cbaser,
> +	},
> +	{
> +		.base		= GITS_CWRITER,
> +		.len		= 0x08,
> +		.bits_per_irq	= 0,
> +		.handle_mmio	= handle_mmio_gits_cwriter,
> +	},
> +	{
> +		.base		= GITS_CREADR,
> +		.len		= 0x08,
> +		.bits_per_irq	= 0,
> +		.handle_mmio	= handle_mmio_gits_creadr,
> +	},
> +	{
> +		/* We don't need any memory from the guest. */
> +		.base		= GITS_BASER,
> +		.len		= 0x40,
> +		.bits_per_irq	= 0,
> +		.handle_mmio	= handle_mmio_raz_wi,
> +	},
> +	{
> +		.base		= GITS_IDREGS_BASE,
> +		.len		= 0x30,
> +		.bits_per_irq	= 0,
> +		.handle_mmio	= handle_mmio_gits_idregs,
> +	},
> +};
> +
> +/* This is called on setting the LPI enable bit in the redistributor. */
> +void vgic_enable_lpis(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +int vits_init(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct vgic_its *its = &dist->its;
> +
> +	spin_lock_init(&its->lock);
> +
> +	its->enabled = false;
> +
> +	return -ENXIO;
> +}
> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
> new file mode 100644
> index 0000000..5dc8e2f
> --- /dev/null
> +++ b/virt/kvm/arm/its-emul.h
> @@ -0,0 +1,35 @@
> +/*
> + * GICv3 ITS emulation definitions
> + *
> + * Copyright (C) 2015 ARM Ltd.
> + * Author: Andre Przywara <andre.przywara@arm.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef __KVM_ITS_EMUL_H__
> +#define __KVM_ITS_EMUL_H__
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include <asm/kvm_emulate.h>
> +#include <asm/kvm_arm.h>
> +#include <asm/kvm_mmu.h>
> +
> +#include "vgic.h"
> +
> +void vgic_enable_lpis(struct kvm_vcpu *vcpu);
> +int vits_init(struct kvm *kvm);
> +
> +#endif
> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
> index 5269ad1..f5865e7 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -48,6 +48,7 @@
>  #include <asm/kvm_mmu.h>
>  
>  #include "vgic.h"
> +#include "its-emul.h"
>  
>  static bool handle_mmio_rao_wi(struct kvm_vcpu *vcpu,
>  			       struct kvm_exit_mmio *mmio, phys_addr_t offset)
> @@ -530,9 +531,20 @@ static bool handle_mmio_ctlr_redist(struct kvm_vcpu *vcpu,
>  				    struct kvm_exit_mmio *mmio,
>  				    phys_addr_t offset)
>  {
> -	/* since we don't support LPIs, this register is zero for now */
> -	vgic_reg_access(mmio, NULL, offset,
> -			ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +	u32 reg;
> +
> +	if (!vgic_has_its(vcpu->kvm)) {
> +		vgic_reg_access(mmio, NULL, offset,
> +				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
> +		return false;
> +	}
can't we remove above block and ...
> +	reg = dist->lpis_enabled ? GICR_CTLR_ENABLE_LPIS : 0;
> +	vgic_reg_access(mmio, &reg, offset,
> +			ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
> +	if (!dist->lpis_enabled && (reg & GICR_CTLR_ENABLE_LPIS
add vgic_has_its(vcpu->kvm) && above?

Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric
)) {
> +		/* Eventually do something */
> +	}
>  	return false;
>  }
>  
> @@ -861,6 +873,12 @@ static int vgic_v3_map_resources(struct kvm *kvm,
>  		rdbase += GIC_V3_REDIST_SIZE;
>  	}
>  
> +	if (vgic_has_its(kvm)) {
> +		ret = vits_init(kvm);
> +		if (ret)
> +			goto out_unregister;
> +	}
> +
>  	dist->redist_iodevs = iodevs;
>  	dist->ready = true;
>  	goto out;
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 09/15] KVM: arm64: implement basic ITS register handlers
  2015-07-10 14:21 ` [PATCH v2 09/15] KVM: arm64: implement basic ITS register handlers Andre Przywara
@ 2015-08-13 15:25   ` Eric Auger
  2015-08-25 10:23     ` Andre Przywara
  2015-10-02  7:51   ` Pavel Fedin
  1 sibling, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-13 15:25 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/10/2015 04:21 PM, Andre Przywara wrote:
> Add emulation for some basic MMIO registers used in the ITS emulation.
> This includes:
> - GITS_{CTLR,TYPER,IIDR}
> - ID registers
> - GITS_{CBASER,CREADR,CWRITER}
>   those implement the ITS command buffer handling
> 
> Most of the handlers are pretty straight forward
straightforward?
, but CWRITER goes
> some extra miles to allow fine grained locking. The idea here
> is to let only the first instance iterate through the command ring
> buffer, CWRITER accesses on other VCPUs meanwhile will be picked up
> by that first instance and handled as well. The ITS lock is thus only
> hold for very small periods of time and is dropped before the actual
> command handler is called.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h             |   3 +
>  include/linux/irqchip/arm-gic-v3.h |   8 ++
>  virt/kvm/arm/its-emul.c            | 205 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h            |   1 +
>  virt/kvm/arm/vgic-v3-emul.c        |   2 +
>  5 files changed, 219 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 9e9d4aa..b432055 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -159,6 +159,9 @@ struct vgic_io_device {
>  struct vgic_its {
>  	bool			enabled;
>  	spinlock_t		lock;
> +	u64			cbaser;
> +	int			creadr;
> +	int			cwriter;
>  };
>  
>  struct vgic_dist {
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index df4e527..0b450c7 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -179,15 +179,23 @@
>  #define GITS_BASER			0x0100
>  #define GITS_IDREGS_BASE		0xffd0
>  #define GITS_PIDR2			GICR_PIDR2
> +#define GITS_PIDR4			0xffd0
> +#define GITS_CIDR0			0xfff0
> +#define GITS_CIDR1			0xfff4
> +#define GITS_CIDR2			0xfff8
> +#define GITS_CIDR3			0xfffc
>  
>  #define GITS_TRANSLATER			0x10040
>  
>  #define GITS_CTLR_ENABLE		(1U << 0)
>  #define GITS_CTLR_QUIESCENT		(1U << 31)
>  
> +#define GITS_TYPER_PLPIS		(1UL << 0)
> +#define GITS_TYPER_IDBITS_SHIFT		8
>  #define GITS_TYPER_DEVBITS_SHIFT	13
>  #define GITS_TYPER_DEVBITS(r)		((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
>  #define GITS_TYPER_PTA			(1UL << 19)
> +#define GITS_TYPER_HWCOLLCNT_SHIFT	24
>  
>  #define GITS_CBASER_VALID		(1UL << 63)
>  #define GITS_CBASER_nCnB		(0UL << 59)
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index 659dd39..b498f06 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -32,10 +32,62 @@
>  #include "vgic.h"
>  #include "its-emul.h"
>  
> +#define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
> +
> +/* The distributor lock is held by the VGIC MMIO handler. */
>  static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
>  				  struct kvm_exit_mmio *mmio,
>  				  phys_addr_t offset)
>  {
> +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> +	u32 reg;
> +	bool was_enabled;
> +
> +	switch (offset & ~3) {
> +	case 0x00:		/* GITS_CTLR */
> +		/* We never defer any command execution. */
> +		reg = GITS_CTLR_QUIESCENT;
> +		if (its->enabled)
> +			reg |= GITS_CTLR_ENABLE;
> +		was_enabled = its->enabled;
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
> +		its->enabled = !!(reg & GITS_CTLR_ENABLE);
> +		return !was_enabled && its->enabled;
> +	case 0x04:		/* GITS_IIDR */
> +		reg = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
> +		break;
> +	case 0x08:		/* GITS_TYPER */
> +		/*
> +		 * We use linear CPU numbers for redistributor addressing,
> +		 * so GITS_TYPER.PTA is 0.
> +		 * To avoid memory waste on the guest side, we keep the
> +		 * number of IDBits and DevBits low for the time being.
> +		 * This could later be made configurable by userland.
> +		 * Since we have all collections in linked list, we claim
> +		 * that we can hold all of the collection tables in our
> +		 * own memory and that the ITT entry size is 1 byte (the
> +		 * smallest possible one).
> +		 */
> +		reg = GITS_TYPER_PLPIS;
> +		reg |= 0xff << GITS_TYPER_HWCOLLCNT_SHIFT;
> +		reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT;
> +		reg |= 0x0f << GITS_TYPER_IDBITS_SHIFT;
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
> +		break;
> +	case 0x0c:
> +		/* The upper 32bits of TYPER are all 0 for the time being.
> +		 * Should we need more than 256 collections, we can enable
> +		 * some bits in here.
> +		 */
> +		vgic_reg_access(mmio, NULL, offset & 3,
> +				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
> +		break;
> +	}
> +
>  	return false;
>  }
>  
> @@ -43,20 +95,142 @@ static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
>  				    struct kvm_exit_mmio *mmio,
>  				    phys_addr_t offset)
>  {
> +	u32 reg = 0;
> +	int idreg = (offset & ~3) + GITS_IDREGS_BASE;
> +
> +	switch (idreg) {
> +	case GITS_PIDR2:
> +		reg = GIC_PIDR2_ARCH_GICv3;
> +		break;
> +	case GITS_PIDR4:
> +		/* This is a 64K software visible page */
> +		reg = 0x40;
> +		break;
> +	/* Those are the ID registers for (any) GIC. */
> +	case GITS_CIDR0:
> +		reg = 0x0d;
> +		break;
> +	case GITS_CIDR1:
> +		reg = 0xf0;
> +		break;
> +	case GITS_CIDR2:
> +		reg = 0x05;
> +		break;
> +	case GITS_CIDR3:
> +		reg = 0xb1;
> +		break;
> +	}
> +	vgic_reg_access(mmio, &reg, offset & 3,
> +			ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
>  	return false;
>  }
>  
> +static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
> +{
> +	return -ENODEV;
> +}
> +
>  static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
>  				    struct kvm_exit_mmio *mmio,
>  				    phys_addr_t offset)
>  {
> +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> +	int mode = ACCESS_READ_VALUE;
> +
> +	mode |= its->enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
> +
> +	vgic_handle_base_register(vcpu, mmio, offset, &its->cbaser, mode);
> +
> +	/* Writing CBASER resets the read pointer. */
> +	if (mmio->is_write)
> +		its->creadr = 0;
> +
>  	return false;
>  }
>  
> +static int its_cmd_buffer_size(struct kvm *kvm)
> +{
> +	struct vgic_its *its = &kvm->arch.vgic.its;
> +
> +	return ((its->cbaser & 0xff) + 1) << 12;
> +}
> +
> +static gpa_t its_cmd_buffer_base(struct kvm *kvm)
> +{
> +	struct vgic_its *its = &kvm->arch.vgic.its;
> +
> +	return BASER_BASE_ADDRESS(its->cbaser);
> +}
> +
> +/*
> + * By writing to CWRITER the guest announces new commands to be processed.
> + * Since we cannot read from guest memory inside the ITS spinlock, we
> + * iterate over the command buffer (with the lock dropped) until the read
> + * pointer matches the write pointer. Other VCPUs writing this register in the
> + * meantime will just update the write pointer, leaving the command
> + * processing to the first instance of the function.
> + */
I am lost, isn't the dist lock hold by vgic_handle_mmio_access before
calling call_range_handler/range->handle_mmio ?

if confirmed we need to move the command enumeration + execution
somewhere else. Besides that piece of code may deserve to be
encaspulated in a function. what do you think?


>  static bool handle_mmio_gits_cwriter(struct kvm_vcpu *vcpu,
>  				     struct kvm_exit_mmio *mmio,
>  				     phys_addr_t offset)
>  {
> +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> +	gpa_t cbaser = its_cmd_buffer_base(vcpu->kvm);
> +	u64 cmd_buf[4];
> +	u32 reg;
> +	bool finished;
> +
> +	/* The upper 32 bits are RES0 */
> +	if ((offset & ~3) == 0x04) {
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
> +		return false;
> +	}
> +
> +	reg = its->cwriter & 0xfffe0;
> +	vgic_reg_access(mmio, &reg, offset & 3,
> +			ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
> +	if (!mmio->is_write)
> +		return false;
> +
> +	reg &= 0xfffe0;
> +	if (reg > its_cmd_buffer_size(vcpu->kvm))
> +		return false;
> +
> +	spin_lock(&its->lock);
> +
> +	/*
> +	 * If there is still another VCPU handling commands, let this
> +	 * one pick up the new CWRITER and process our new commands as well.
> +	 */
> +	finished = (its->cwriter != its->creadr);
> +	its->cwriter = reg;
> +
> +	spin_unlock(&its->lock);
> +
> +	while (!finished) {
> +		int ret = kvm_read_guest(vcpu->kvm, cbaser + its->creadr,
> +					 cmd_buf, 32);
> +		if (ret) {
> +			/*
> +			 * Gah, we are screwed. Reset CWRITER to that command
> +			 * that we have finished processing and return.
> +			 */
> +			spin_lock(&its->lock);
> +			its->cwriter = its->creadr;
> +			spin_unlock(&its->lock);
> +			break;
> +		}
> +		vits_handle_command(vcpu, cmd_buf);
> +
> +		spin_lock(&its->lock);
> +		its->creadr += 32;
> +		if (its->creadr == its_cmd_buffer_size(vcpu->kvm))
> +			its->creadr = 0;
> +		finished = (its->creadr == its->cwriter);
> +		spin_unlock(&its->lock);
> +	}
> +
>  	return false;
>  }
>  
> @@ -64,6 +238,20 @@ static bool handle_mmio_gits_creadr(struct kvm_vcpu *vcpu,
>  				    struct kvm_exit_mmio *mmio,
>  				    phys_addr_t offset)
>  {
> +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> +	u32 reg;
> +
> +	switch (offset & ~3) {
> +	case 0x00:
> +		reg = its->creadr & 0xfffe0;
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
> +		break;
> +	case 0x04:
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
> +		break;
> +	}
>  	return false;
>  }
>  
> @@ -117,9 +305,26 @@ int vits_init(struct kvm *kvm)
>  	struct vgic_dist *dist = &kvm->arch.vgic;
>  	struct vgic_its *its = &dist->its;
>  
> +	dist->pendbaser = kmalloc(sizeof(u64) * dist->nr_cpus, GFP_KERNEL);
check_patch advises to use kmalloc_array here (warning). or kcalloc?

Eric

> +	if (!dist->pendbaser)
> +		return -ENOMEM;
> +
>  	spin_lock_init(&its->lock);
>  
>  	its->enabled = false;
>  
>  	return -ENXIO;
>  }
> +
> +void vits_destroy(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct vgic_its *its = &dist->its;
> +
> +	if (!vgic_has_its(kvm))
> +		return;
> +
> +	kfree(dist->pendbaser);
> +
> +	its->enabled = false;
> +}
> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
> index 5dc8e2f..472a6d0 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -31,5 +31,6 @@
>  
>  void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>  int vits_init(struct kvm *kvm);
> +void vits_destroy(struct kvm *kvm);
>  
>  #endif
> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
> index f5865e7..49be3c3 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -928,6 +928,8 @@ static void vgic_v3_destroy_model(struct kvm *kvm)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
>  
> +	vits_destroy(kvm);
> +
>  	kfree(dist->irq_spi_mpidr);
>  	dist->irq_spi_mpidr = NULL;
>  }
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 10/15] KVM: arm64: add data structures to model ITS interrupt translation
  2015-07-10 14:21 ` [PATCH v2 10/15] KVM: arm64: add data structures to model ITS interrupt translation Andre Przywara
@ 2015-08-13 15:46   ` Eric Auger
  2015-08-25 11:15     ` Andre Przywara
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-13 15:46 UTC (permalink / raw)
  To: linux-arm-kernel


On 07/10/2015 04:21 PM, Andre Przywara wrote:
> The GICv3 Interrupt Translation Service (ITS) uses tables in memory
> to allow a sophisticated interrupt routing. It features device tables,
> an interrupt table per device and a table connecting "collections" to
> actual CPUs (aka. redistributors in the GICv3 lingo).
> Since the interrupt numbers for the LPIs are allocated quite sparsely
> and the range can be quite huge (8192 LPIs being the minimum), using
> bitmaps or arrays for storing information is a waste of memory.
> We use linked lists instead, which we iterate linearily. This works
> very well with the actual number of LPIs/MSIs in the guest being
> quite low. Should the number of LPIs exceed the number where iterating
> through lists seems acceptable, we can later revisit this and use more
> efficient data structures.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h  |  3 +++
>  virt/kvm/arm/its-emul.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 51 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index b432055..1648668 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -25,6 +25,7 @@
>  #include <linux/spinlock.h>
>  #include <linux/types.h>
>  #include <kvm/iodev.h>
> +#include <linux/list.h>
>  
>  #define VGIC_NR_IRQS_LEGACY	256
>  #define VGIC_NR_SGIS		16
> @@ -162,6 +163,8 @@ struct vgic_its {
>  	u64			cbaser;
>  	int			creadr;
>  	int			cwriter;
> +	struct list_head	device_list;
> +	struct list_head	collection_list;
>  };
>  
>  struct vgic_dist {
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index b498f06..7f217fa 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -21,6 +21,7 @@
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
>  #include <linux/interrupt.h>
> +#include <linux/list.h>
>  
>  #include <linux/irqchip/arm-gic-v3.h>
>  #include <kvm/arm_vgic.h>
> @@ -32,6 +33,25 @@
>  #include "vgic.h"
>  #include "its-emul.h"
>  
> +struct its_device {
> +	struct list_head dev_list;
> +	struct list_head itt;
> +	u32 device_id;
> +};
> +
> +struct its_collection {
> +	struct list_head coll_list;
> +	u32 collection_id;
> +	u32 target_addr;
> +};
> +
> +struct its_itte {
> +	struct list_head itte_list;
> +	struct its_collection *collection;
> +	u32 lpi;
> +	u32 event_id;
> +};
> +
>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>  
>  /* The distributor lock is held by the VGIC MMIO handler. */
> @@ -311,6 +331,9 @@ int vits_init(struct kvm *kvm)
>  
>  	spin_lock_init(&its->lock);
>  
> +	INIT_LIST_HEAD(&its->device_list);
> +	INIT_LIST_HEAD(&its->collection_list);
> +
>  	its->enabled = false;
>  
>  	return -ENXIO;
> @@ -320,11 +343,36 @@ void vits_destroy(struct kvm *kvm)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
>  	struct vgic_its *its = &dist->its;
> +	struct its_device *dev;
> +	struct its_itte *itte;
> +	struct list_head *dev_cur, *dev_temp;
> +	struct list_head *cur, *temp;
>  
>  	if (!vgic_has_its(kvm))
>  		return;
>  
> +	if (!its->device_list.next)
Why not using list_empty? But I think I would simply remove this since
the empty case if handle below...
> +		return;
> +
> +	spin_lock(&its->lock);
> +	list_for_each_safe(dev_cur, dev_temp, &its->device_list) {
> +		dev = container_of(dev_cur, struct its_device, dev_list);
isn't the usage of list_for_each_entry_safe more synthetic here?
> +		list_for_each_safe(cur, temp, &dev->itt) {
> +			itte = (container_of(cur, struct its_itte, itte_list));
same

Eric
> +			list_del(cur);
> +			kfree(itte);
> +		}
> +		list_del(dev_cur);
> +		kfree(dev);
> +	}
> +
> +	list_for_each_safe(cur, temp, &its->collection_list) {
> +		list_del(cur);
> +		kfree(container_of(cur, struct its_collection, coll_list));
> +	}
> +
>  	kfree(dist->pendbaser);
>  
>  	its->enabled = false;
> +	spin_unlock(&its->lock);
>  }
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 12/15] KVM: arm64: sync LPI configuration and pending tables
  2015-07-10 14:21 ` [PATCH v2 12/15] KVM: arm64: sync LPI configuration and pending tables Andre Przywara
@ 2015-08-14 11:58   ` Eric Auger
  2015-08-14 12:35     ` Eric Auger
  2015-08-25 15:27     ` Andre Przywara
  0 siblings, 2 replies; 69+ messages in thread
From: Eric Auger @ 2015-08-14 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/10/2015 04:21 PM, Andre Przywara wrote:
> The LPI configuration and pending tables of the GICv3 LPIs are held
> in tables in (guest) memory. To achieve reasonable performance, we
> cache this data in our own data structures, so we need to sync those
> two views from time to time. This behaviour is well described in the
> GICv3 spec and is also exercised by hardware, so the sync points are
> well known.
> 
> Provide functions that read the guest memory and store the
> information from the configuration and pending tables in the kernel.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
would help to have change log between v1 -> v2 (valid for the whole series)
>  include/kvm/arm_vgic.h  |   2 +
>  virt/kvm/arm/its-emul.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h |   3 ++
>  3 files changed, 129 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 2a67a10..323c33a 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -167,6 +167,8 @@ struct vgic_its {
>  	int			cwriter;
>  	struct list_head	device_list;
>  	struct list_head	collection_list;
> +	/* memory used for buffering guest's memory */
> +	void			*buffer_page;
>  };
>  
>  struct vgic_dist {
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index b9c40d7..05245cb 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -50,6 +50,7 @@ struct its_itte {
>  	struct its_collection *collection;
>  	u32 lpi;
>  	u32 event_id;
> +	u8 priority;
>  	bool enabled;
>  	unsigned long *pending;
>  };
> @@ -70,8 +71,124 @@ static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
>  	return NULL;
>  }
>  
> +#define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
> +#define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
> +
> +/* stores the priority and enable bit for a given LPI */
> +static void update_lpi_config(struct kvm *kvm, struct its_itte *itte, u8 prop)
> +{
> +	itte->priority = LPI_PROP_PRIORITY(prop);
> +	itte->enabled  = LPI_PROP_ENABLE_BIT(prop);
> +}
> +
> +#define GIC_LPI_OFFSET 8192
> +
> +/* We scan the table in chunks the size of the smallest page size */
4kB chunks?
> +#define CHUNK_SIZE 4096U
> +
>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>  
> +static int nr_idbits_propbase(u64 propbaser)
> +{
> +	int nr_idbits = (1U << (propbaser & 0x1f)) + 1;
> +
> +	return max(nr_idbits, INTERRUPT_ID_BITS_ITS);
> +}
> +
> +/*
> + * Scan the whole LPI configuration table and put the LPI configuration
> + * data in our own data structures. This relies on the LPI being
> + * mapped before.
> + */
> +static bool its_update_lpis_configuration(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	u8 *prop = dist->its.buffer_page;
> +	u32 tsize;
> +	gpa_t propbase;
> +	int lpi = GIC_LPI_OFFSET;
> +	struct its_itte *itte;
> +	struct its_device *device;
> +	int ret;
> +
> +	propbase = BASER_BASE_ADDRESS(dist->propbaser);
> +	tsize = nr_idbits_propbase(dist->propbaser);
> +
> +	while (tsize > 0) {
> +		int chunksize = min(tsize, CHUNK_SIZE);
> +
> +		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
I think you still have the spin_lock issue  since if my understanding is
correct this is called from
vgic_handle_mmio_access/vcall_range_handler/gic_enable_lpis
where vgic_handle_mmio_access. Or does it take another path?

Shouldn't we create a new kvm_io_device to avoid holding the dist lock?

Eric
> +		if (ret)
> +			return false;
> +
> +		spin_lock(&dist->its.lock);
> +		/*
> +		 * Updating the status for all allocated LPIs. We catch
> +		 * those LPIs that get disabled. We really don't care
> +		 * about unmapped LPIs, as they need to be updated
> +		 * later manually anyway once they get mapped.
> +		 */
> +		for_each_lpi(device, itte, kvm) {
> +			if (itte->lpi < lpi || itte->lpi >= lpi + chunksize)
> +				continue;
> +
> +			update_lpi_config(kvm, itte, prop[itte->lpi - lpi]);
> +		}
> +		spin_unlock(&dist->its.lock);
> +		tsize -= chunksize;
> +		lpi += chunksize;
> +		propbase += chunksize;
> +	}
> +
> +	return true;
> +}
> +
> +/*
> + * Scan the whole LPI pending table and sync the pending bit in there
> + * with our own data structures. This relies on the LPI being
> + * mapped before.
> + */
> +static bool its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +	unsigned long *pendmask = dist->its.buffer_page;
> +	u32 nr_lpis = VITS_NR_LPIS;
> +	gpa_t pendbase;
> +	int lpi = 0;
> +	struct its_itte *itte;
> +	struct its_device *device;
> +	int ret;
> +	int lpi_bit, nr_bits;
> +
> +	pendbase = BASER_BASE_ADDRESS(dist->pendbaser[vcpu->vcpu_id]);
> +
> +	while (nr_lpis > 0) {
> +		nr_bits = min(nr_lpis, CHUNK_SIZE * 8);
> +
> +		ret = kvm_read_guest(vcpu->kvm, pendbase, pendmask,
> +				     nr_bits / 8);
> +		if (ret)
> +			return false;
> +
> +		spin_lock(&dist->its.lock);
> +		for_each_lpi(device, itte, vcpu->kvm) {
> +			lpi_bit = itte->lpi - lpi;
> +			if (lpi_bit < 0 || lpi_bit >= nr_bits)
> +				continue;
> +			if (test_bit(lpi_bit, pendmask))
> +				__set_bit(vcpu->vcpu_id, itte->pending);
> +			else
> +				__clear_bit(vcpu->vcpu_id, itte->pending);
> +		}
> +		spin_unlock(&dist->its.lock);
> +		nr_lpis -= nr_bits;
> +		lpi += nr_bits;
> +		pendbase += nr_bits / 8;
> +	}
> +
> +	return true;
> +}
> +
>  /* The distributor lock is held by the VGIC MMIO handler. */
>  static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
>  				  struct kvm_exit_mmio *mmio,
> @@ -389,6 +506,8 @@ static const struct vgic_io_range vgicv3_its_ranges[] = {
>  /* This is called on setting the LPI enable bit in the redistributor. */
>  void vgic_enable_lpis(struct kvm_vcpu *vcpu)
>  {
> +	its_update_lpis_configuration(vcpu->kvm);
> +	its_sync_lpi_pending_table(vcpu);
>  }
>  
>  int vits_init(struct kvm *kvm)
> @@ -400,6 +519,10 @@ int vits_init(struct kvm *kvm)
>  	if (!dist->pendbaser)
>  		return -ENOMEM;
>  
> +	its->buffer_page = kmalloc(CHUNK_SIZE, GFP_KERNEL);
> +	if (!its->buffer_page)
> +		return -ENOMEM;
> +
>  	spin_lock_init(&its->lock);
>  
>  	INIT_LIST_HEAD(&its->device_list);
> @@ -442,6 +565,7 @@ void vits_destroy(struct kvm *kvm)
>  		kfree(container_of(cur, struct its_collection, coll_list));
>  	}
>  
> +	kfree(its->buffer_page);
>  	kfree(dist->pendbaser);
>  
>  	its->enabled = false;
> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
> index cc5d5ff..cbc3877 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -29,6 +29,9 @@
>  
>  #include "vgic.h"
>  
> +#define INTERRUPT_ID_BITS_ITS 16
> +#define VITS_NR_LPIS (1U << INTERRUPT_ID_BITS_ITS)
> +
>  void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>  int vits_init(struct kvm *kvm);
>  void vits_destroy(struct kvm *kvm);
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 11/15] KVM: arm64: handle pending bit for LPIs in ITS emulation
  2015-07-10 14:21 ` [PATCH v2 11/15] KVM: arm64: handle pending bit for LPIs in ITS emulation Andre Przywara
@ 2015-08-14 11:58   ` Eric Auger
  2015-08-25 14:34     ` Andre Przywara
  2015-10-07  8:39   ` Pavel Fedin
  1 sibling, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-14 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/10/2015 04:21 PM, Andre Przywara wrote:
> As the actual LPI number in a guest can be quite high, but is mostly
> assigned using a very sparse allocation scheme, bitmaps and arrays
> for storing the virtual interrupt status are a waste of memory.
> We use our equivalent of the "Interrupt Translation Table Entry"
> (ITTE) to hold this extra status information for a virtual LPI.
> As the normal VGIC code cannot use it's fancy bitmaps to manage
> pending interrupts, we provide a hook in the VGIC code to let the
> ITS emulation handle the list register queueing itself.
> LPIs are located in a separate number range (>=8192), so
> distinguishing them is easy. With LPIs being only edge-triggered, we
> get away with a less complex IRQ handling.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h      |  2 ++
>  virt/kvm/arm/its-emul.c     | 71 ++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h     |  3 ++
>  virt/kvm/arm/vgic-v3-emul.c |  2 ++
>  virt/kvm/arm/vgic.c         | 72 ++++++++++++++++++++++++++++++++++-----------
>  5 files changed, 133 insertions(+), 17 deletions(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 1648668..2a67a10 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -147,6 +147,8 @@ struct vgic_vm_ops {
>  	int	(*init_model)(struct kvm *);
>  	void	(*destroy_model)(struct kvm *);
>  	int	(*map_resources)(struct kvm *, const struct vgic_params *);
> +	bool	(*queue_lpis)(struct kvm_vcpu *);
> +	void	(*unqueue_lpi)(struct kvm_vcpu *, int irq);
>  };
>  
>  struct vgic_io_device {
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index 7f217fa..b9c40d7 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -50,8 +50,26 @@ struct its_itte {
>  	struct its_collection *collection;
>  	u32 lpi;
>  	u32 event_id;
> +	bool enabled;
> +	unsigned long *pending;
>  };
>  
> +#define for_each_lpi(dev, itte, kvm) \
> +	list_for_each_entry(dev, &(kvm)->arch.vgic.its.device_list, dev_list) \
> +		list_for_each_entry(itte, &(dev)->itt, itte_list)
> +
You have a checkpatch error here:

ERROR: Macros with complex values should be enclosed in parentheses
#52: FILE: virt/kvm/arm/its-emul.c:57:
+#define for_each_lpi(dev, itte, kvm) \
+	list_for_each_entry(dev, &(kvm)->arch.vgic.its.device_list, dev_list) \
+		list_for_each_entry(itte, &(dev)->itt, itte_list)

> +static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
> +{
can't we have the same LPI present in different interrupt translation
tables? I don't know it is a sensible setting but I did not succeed in
finding it was not possible.
> +	struct its_device *device;
> +	struct its_itte *itte;
> +
> +	for_each_lpi(device, itte, kvm) {
> +		if (itte->lpi == lpi)
> +			return itte;
> +	}
> +	return NULL;
> +}
> +
>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>  
>  /* The distributor lock is held by the VGIC MMIO handler. */
> @@ -145,6 +163,59 @@ static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
>  	return false;
>  }
>  
> +/*
> + * Find all enabled and pending LPIs and queue them into the list
> + * registers.
> + * The dist lock is held by the caller.
> + */
> +bool vits_queue_lpis(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> +	struct its_device *device;
> +	struct its_itte *itte;
> +	bool ret = true;
> +
> +	if (!vgic_has_its(vcpu->kvm))
> +		return true;
> +	if (!its->enabled || !vcpu->kvm->arch.vgic.lpis_enabled)
> +		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)
> +			continue;
> +
> +		__clear_bit(vcpu->vcpu_id, itte->pending);
> +
> +		ret &= vgic_queue_irq(vcpu, 0, itte->lpi);
what if the vgic_queue_irq fails since no LR can be found, the
itte->pending was cleared so we forget that LPI? shouldn't we restore
the pending state in ITT? in vgic_queue_hwirq the state change only is
performed if the vgic_queue_irq succeeds
> +	}
> +
> +	spin_unlock(&its->lock);
> +	return ret;
> +}
> +
> +/* Called with the distributor lock held by the caller. */
> +void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi)
I was a bit confused by the name of the function, with regard to
existing vgic_unqueue_irqs which restores the states in accordance to
what we have in LR. Wouldn't it make sense to call it
vits_lpi_set_pending(vcpu, lpi) or something that looks more similar to
vgic_dist_irq_set_pending setter which I think it mirrors.

> +{
> +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> +	struct its_itte *itte;
> +
> +	spin_lock(&its->lock);
> +
> +	/* Find the right ITTE and put the pending state back in there */
> +	itte = find_itte_by_lpi(vcpu->kvm, lpi);
> +	if (itte)
> +		__set_bit(vcpu->vcpu_id, itte->pending);
> +
> +	spin_unlock(&its->lock);
> +}
> +
>  static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
>  {
>  	return -ENODEV;
> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
> index 472a6d0..cc5d5ff 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -33,4 +33,7 @@ void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>  int vits_init(struct kvm *kvm);
>  void vits_destroy(struct kvm *kvm);
>  
> +bool vits_queue_lpis(struct kvm_vcpu *vcpu);
> +void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int irq);
> +
>  #endif
> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
> index 49be3c3..4132c26 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -948,6 +948,8 @@ void vgic_v3_init_emulation(struct kvm *kvm)
>  	dist->vm_ops.init_model = vgic_v3_init_model;
>  	dist->vm_ops.destroy_model = vgic_v3_destroy_model;
>  	dist->vm_ops.map_resources = vgic_v3_map_resources;
> +	dist->vm_ops.queue_lpis = vits_queue_lpis;
> +	dist->vm_ops.unqueue_lpi = vits_unqueue_lpi;
>  
>  	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 49ee92b..9dfd094 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -95,6 +95,20 @@ static bool queue_sgi(struct kvm_vcpu *vcpu, int irq)
>  	return vcpu->kvm->arch.vgic.vm_ops.queue_sgi(vcpu, irq);
>  }
>  
> +static bool vgic_queue_lpis(struct kvm_vcpu *vcpu)
> +{
> +	if (vcpu->kvm->arch.vgic.vm_ops.queue_lpis)
> +		return vcpu->kvm->arch.vgic.vm_ops.queue_lpis(vcpu);
> +	else
> +		return true;
> +}
> +
> +static void vgic_unqueue_lpi(struct kvm_vcpu *vcpu, int irq)
> +{
> +	if (vcpu->kvm->arch.vgic.vm_ops.unqueue_lpi)
> +		vcpu->kvm->arch.vgic.vm_ops.unqueue_lpi(vcpu, irq);
> +}
> +
>  int kvm_vgic_map_resources(struct kvm *kvm)
>  {
>  	return kvm->arch.vgic.vm_ops.map_resources(kvm, vgic);
> @@ -1135,6 +1149,10 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
>  	for_each_clear_bit(lr, elrsr_ptr, vgic->nr_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)) {
>  			vlr.state = 0;
>  			vgic_set_lr(vcpu, lr, vlr);
> @@ -1147,25 +1165,33 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
>  static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>  				 int lr_nr, int sgi_source_id)
>  {
> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>  	struct vgic_lr vlr;
>  
>  	vlr.state = 0;
>  	vlr.irq = irq;
>  	vlr.source = sgi_source_id;
>  
> -	if (vgic_irq_is_active(vcpu, irq)) {
> -		vlr.state |= LR_STATE_ACTIVE;
> -		kvm_debug("Set active, clear distributor: 0x%x\n", vlr.state);
> -		vgic_irq_clear_active(vcpu, irq);
> -		vgic_update_state(vcpu->kvm);
> -	} else if (vgic_dist_irq_is_pending(vcpu, irq)) {
> -		vlr.state |= LR_STATE_PENDING;
> -		kvm_debug("Set pending: 0x%x\n", vlr.state);
> -	}
> -
> -	if (!vgic_irq_is_edge(vcpu, irq))
> -		vlr.state |= LR_EOI_INT;
> +	/* We care only about state for SGIs/PPIs/SPIs, not for LPIs */
> +	if (irq < dist->nr_irqs) {
> +		if (vgic_irq_is_active(vcpu, irq)) {
> +			vlr.state |= LR_STATE_ACTIVE;
> +			kvm_debug("Set active, clear distributor: 0x%x\n",
> +				  vlr.state);
> +			vgic_irq_clear_active(vcpu, irq);
> +			vgic_update_state(vcpu->kvm);
> +		} else if (vgic_dist_irq_is_pending(vcpu, irq)) {
> +			vlr.state |= LR_STATE_PENDING;
> +			kvm_debug("Set pending: 0x%x\n", vlr.state);
> +		}
>  
> +		if (!vgic_irq_is_edge(vcpu, irq))
> +			vlr.state |= LR_EOI_INT;
> +	} else {
> +		/* If this is an LPI, it can only be pending */
> +		if (irq >= 8192)
> +			vlr.state |= LR_STATE_PENDING;
> +	}
>  	vgic_set_lr(vcpu, lr_nr, vlr);
>  	vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
>  }
> @@ -1177,7 +1203,6 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>   */
>  bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>  {
> -	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>  	u64 elrsr = vgic_get_elrsr(vcpu);
>  	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
>  	int lr;
> @@ -1185,7 +1210,6 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>  	/* Sanitize the input... */
>  	BUG_ON(sgi_source_id & ~7);
>  	BUG_ON(sgi_source_id && irq >= VGIC_NR_SGIS);
> -	BUG_ON(irq >= dist->nr_irqs);
Is it safe to remove that check. What if it is attempted to inject an
SPI larger than supported. I think you should refine the check but not
remove it.
>  
>  	kvm_debug("Queue IRQ%d\n", irq);
>  
> @@ -1265,8 +1289,12 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>  			overflow = 1;
>  	}
>  
> -
> -
> +	/*
> +	 * LPIs are not mapped in our bitmaps, so we leave the iteration
> +	 * to the ITS emulation code.
> +	 */
> +	if (!vgic_queue_lpis(vcpu))
> +		overflow = 1;
>  
>  epilog:
>  	if (overflow) {
> @@ -1387,6 +1415,16 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>  	for_each_clear_bit(lr_nr, elrsr_ptr, vgic_cpu->nr_lr) {
>  		vlr = vgic_get_lr(vcpu, lr_nr);
>  
> +		/* LPIs are handled separately */
> +		if (vlr.irq >= 8192) {
> +			/* We just need to take care about still pending LPIs */
> +			if (vlr.state & LR_STATE_PENDING) {
> +				vgic_unqueue_lpi(vcpu, vlr.irq);
> +				pending = true;
> +			}
> +			continue;
don't we need to reset the LR & update elrsr?
> +		}
> +
>  		BUG_ON(!(vlr.state & LR_STATE_MASK));
>  		pending = true;
>  
> @@ -1411,7 +1449,7 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>  	}
>  	vgic_update_state(vcpu->kvm);
>  
> -	/* vgic_update_state would not cover only-active IRQs */
> +	/* vgic_update_state would not cover only-active IRQs or LPIs */
>  	if (pending)
>  		set_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu);
>  }
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 12/15] KVM: arm64: sync LPI configuration and pending tables
  2015-08-14 11:58   ` Eric Auger
@ 2015-08-14 12:35     ` Eric Auger
  2015-08-25 15:47       ` Andre Przywara
  2015-08-25 15:27     ` Andre Przywara
  1 sibling, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-14 12:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/14/2015 01:58 PM, Eric Auger wrote:
> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>> The LPI configuration and pending tables of the GICv3 LPIs are held
>> in tables in (guest) memory. To achieve reasonable performance, we
>> cache this data in our own data structures, so we need to sync those
>> two views from time to time. This behaviour is well described in the
>> GICv3 spec and is also exercised by hardware, so the sync points are
>> well known.
>>
>> Provide functions that read the guest memory and store the
>> information from the configuration and pending tables in the kernel.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
> would help to have change log between v1 -> v2 (valid for the whole series)
>>  include/kvm/arm_vgic.h  |   2 +
>>  virt/kvm/arm/its-emul.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/its-emul.h |   3 ++
>>  3 files changed, 129 insertions(+)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 2a67a10..323c33a 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -167,6 +167,8 @@ struct vgic_its {
>>  	int			cwriter;
>>  	struct list_head	device_list;
>>  	struct list_head	collection_list;
>> +	/* memory used for buffering guest's memory */
>> +	void			*buffer_page;
>>  };
>>  
>>  struct vgic_dist {
>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>> index b9c40d7..05245cb 100644
>> --- a/virt/kvm/arm/its-emul.c
>> +++ b/virt/kvm/arm/its-emul.c
>> @@ -50,6 +50,7 @@ struct its_itte {
>>  	struct its_collection *collection;
>>  	u32 lpi;
>>  	u32 event_id;
>> +	u8 priority;
>>  	bool enabled;
>>  	unsigned long *pending;
>>  };
>> @@ -70,8 +71,124 @@ static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
>>  	return NULL;
>>  }
>>  
>> +#define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
>> +#define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
>> +
>> +/* stores the priority and enable bit for a given LPI */
>> +static void update_lpi_config(struct kvm *kvm, struct its_itte *itte, u8 prop)
>> +{
>> +	itte->priority = LPI_PROP_PRIORITY(prop);
>> +	itte->enabled  = LPI_PROP_ENABLE_BIT(prop);
>> +}
>> +
>> +#define GIC_LPI_OFFSET 8192
>> +
>> +/* We scan the table in chunks the size of the smallest page size */
> 4kB chunks?
>> +#define CHUNK_SIZE 4096U
>> +
>>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>>  
>> +static int nr_idbits_propbase(u64 propbaser)
>> +{
>> +	int nr_idbits = (1U << (propbaser & 0x1f)) + 1;
>> +
>> +	return max(nr_idbits, INTERRUPT_ID_BITS_ITS);
>> +}
>> +
>> +/*
>> + * Scan the whole LPI configuration table and put the LPI configuration
>> + * data in our own data structures. This relies on the LPI being
>> + * mapped before.
>> + */
>> +static bool its_update_lpis_configuration(struct kvm *kvm)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +	u8 *prop = dist->its.buffer_page;
>> +	u32 tsize;
>> +	gpa_t propbase;
>> +	int lpi = GIC_LPI_OFFSET;
>> +	struct its_itte *itte;
>> +	struct its_device *device;
>> +	int ret;
>> +
>> +	propbase = BASER_BASE_ADDRESS(dist->propbaser);
>> +	tsize = nr_idbits_propbase(dist->propbaser);
>> +
>> +	while (tsize > 0) {
>> +		int chunksize = min(tsize, CHUNK_SIZE);
>> +
>> +		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
> I think you still have the spin_lock issue  since if my understanding is
> correct this is called from
> vgic_handle_mmio_access/vcall_range_handler/gic_enable_lpis
> where vgic_handle_mmio_access. Or does it take another path?
> 
> Shouldn't we create a new kvm_io_device to avoid holding the dist lock?

Sorry I forgot it was the case already. But currently we always register
the same io ops (registration entry point being
vgic_register_kvm_io_dev) and maybe we should have separate dispatcher
function for dist, redit and its?

Eric
> 
> Eric
>> +		if (ret)
>> +			return false;
>> +
>> +		spin_lock(&dist->its.lock);
>> +		/*
>> +		 * Updating the status for all allocated LPIs. We catch
>> +		 * those LPIs that get disabled. We really don't care
>> +		 * about unmapped LPIs, as they need to be updated
>> +		 * later manually anyway once they get mapped.
>> +		 */
>> +		for_each_lpi(device, itte, kvm) {
>> +			if (itte->lpi < lpi || itte->lpi >= lpi + chunksize)
>> +				continue;
>> +
>> +			update_lpi_config(kvm, itte, prop[itte->lpi - lpi]);
>> +		}
>> +		spin_unlock(&dist->its.lock);
>> +		tsize -= chunksize;
>> +		lpi += chunksize;
>> +		propbase += chunksize;
>> +	}
>> +
>> +	return true;
>> +}
>> +
>> +/*
>> + * Scan the whole LPI pending table and sync the pending bit in there
>> + * with our own data structures. This relies on the LPI being
>> + * mapped before.
>> + */
>> +static bool its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>> +	unsigned long *pendmask = dist->its.buffer_page;
>> +	u32 nr_lpis = VITS_NR_LPIS;
>> +	gpa_t pendbase;
>> +	int lpi = 0;
>> +	struct its_itte *itte;
>> +	struct its_device *device;
>> +	int ret;
>> +	int lpi_bit, nr_bits;
>> +
>> +	pendbase = BASER_BASE_ADDRESS(dist->pendbaser[vcpu->vcpu_id]);
>> +
>> +	while (nr_lpis > 0) {
>> +		nr_bits = min(nr_lpis, CHUNK_SIZE * 8);
>> +
>> +		ret = kvm_read_guest(vcpu->kvm, pendbase, pendmask,
>> +				     nr_bits / 8);
>> +		if (ret)
>> +			return false;
>> +
>> +		spin_lock(&dist->its.lock);
>> +		for_each_lpi(device, itte, vcpu->kvm) {
>> +			lpi_bit = itte->lpi - lpi;
>> +			if (lpi_bit < 0 || lpi_bit >= nr_bits)
>> +				continue;
>> +			if (test_bit(lpi_bit, pendmask))
>> +				__set_bit(vcpu->vcpu_id, itte->pending);
>> +			else
>> +				__clear_bit(vcpu->vcpu_id, itte->pending);
>> +		}
>> +		spin_unlock(&dist->its.lock);
>> +		nr_lpis -= nr_bits;
>> +		lpi += nr_bits;
>> +		pendbase += nr_bits / 8;
>> +	}
>> +
>> +	return true;
>> +}
>> +
>>  /* The distributor lock is held by the VGIC MMIO handler. */
>>  static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
>>  				  struct kvm_exit_mmio *mmio,
>> @@ -389,6 +506,8 @@ static const struct vgic_io_range vgicv3_its_ranges[] = {
>>  /* This is called on setting the LPI enable bit in the redistributor. */
>>  void vgic_enable_lpis(struct kvm_vcpu *vcpu)
>>  {
>> +	its_update_lpis_configuration(vcpu->kvm);
>> +	its_sync_lpi_pending_table(vcpu);
>>  }
>>  
>>  int vits_init(struct kvm *kvm)
>> @@ -400,6 +519,10 @@ int vits_init(struct kvm *kvm)
>>  	if (!dist->pendbaser)
>>  		return -ENOMEM;
>>  
>> +	its->buffer_page = kmalloc(CHUNK_SIZE, GFP_KERNEL);
>> +	if (!its->buffer_page)
>> +		return -ENOMEM;
>> +
>>  	spin_lock_init(&its->lock);
>>  
>>  	INIT_LIST_HEAD(&its->device_list);
>> @@ -442,6 +565,7 @@ void vits_destroy(struct kvm *kvm)
>>  		kfree(container_of(cur, struct its_collection, coll_list));
>>  	}
>>  
>> +	kfree(its->buffer_page);
>>  	kfree(dist->pendbaser);
>>  
>>  	its->enabled = false;
>> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
>> index cc5d5ff..cbc3877 100644
>> --- a/virt/kvm/arm/its-emul.h
>> +++ b/virt/kvm/arm/its-emul.h
>> @@ -29,6 +29,9 @@
>>  
>>  #include "vgic.h"
>>  
>> +#define INTERRUPT_ID_BITS_ITS 16
>> +#define VITS_NR_LPIS (1U << INTERRUPT_ID_BITS_ITS)
>> +
>>  void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>>  int vits_init(struct kvm *kvm);
>>  void vits_destroy(struct kvm *kvm);
>>
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 13/15] KVM: arm64: implement ITS command queue command handlers
  2015-07-10 14:21 ` [PATCH v2 13/15] KVM: arm64: implement ITS command queue command handlers Andre Przywara
@ 2015-08-17 13:33   ` Eric Auger
  2015-10-07 14:54     ` Andre Przywara
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-17 13:33 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/10/2015 04:21 PM, Andre Przywara wrote:
> The connection between a device, an event ID, the LPI number and the
> allocated CPU is stored in in-memory tables in a GICv3, but their
> format is not specified by the spec. Instead software uses a command
> queue in a ring buffer to let the ITS implementation use their own
> format.
> Implement handlers for the various ITS commands and let them store
> the requested relation into our own data structures.
> To avoid kmallocs inside the ITS spinlock, we preallocate possibly
> needed memory outside of the lock and free that if it turns out to
> be not needed (mostly error handling).
still dist lock ...?
> Error handling is very basic at this point, as we don't have a good
> way of communicating errors to the guest (usually a SError).
> The INT command handler is missing at this point, as we gain the
> capability of actually injecting MSIs into the guest only later on.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/linux/irqchip/arm-gic-v3.h |   5 +-
>  virt/kvm/arm/its-emul.c            | 497 ++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/its-emul.h            |  11 +
>  3 files changed, 511 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 0b450c7..80db4f6 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -253,7 +253,10 @@
>   */
>  #define GITS_CMD_MAPD			0x08
>  #define GITS_CMD_MAPC			0x09
> -#define GITS_CMD_MAPVI			0x0a
> +#define GITS_CMD_MAPTI			0x0a
> +/* older GIC documentation used MAPVI for this command */
> +#define GITS_CMD_MAPVI			GITS_CMD_MAPTI
> +#define GITS_CMD_MAPI			0x0b
>  #define GITS_CMD_MOVI			0x01
>  #define GITS_CMD_DISCARD		0x0f
>  #define GITS_CMD_INV			0x0c
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index 05245cb..89534c6 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -22,6 +22,7 @@
>  #include <linux/kvm_host.h>
>  #include <linux/interrupt.h>
>  #include <linux/list.h>
> +#include <linux/slab.h>
>  
>  #include <linux/irqchip/arm-gic-v3.h>
>  #include <kvm/arm_vgic.h>
> @@ -55,6 +56,34 @@ struct its_itte {
>  	unsigned long *pending;
>  };
>  
> +static struct its_device *find_its_device(struct kvm *kvm, u32 device_id)
> +{
> +	struct vgic_its *its = &kvm->arch.vgic.its;
> +	struct its_device *device;
> +
> +	list_for_each_entry(device, &its->device_list, dev_list)
> +		if (device_id == device->device_id)
> +			return device;
> +
> +	return NULL;
> +}
> +
> +static struct its_itte *find_itte(struct kvm *kvm, u32 device_id, u32 event_id)
> +{
> +	struct its_device *device;
> +	struct its_itte *itte;
> +
> +	device = find_its_device(kvm, device_id);
> +	if (device == NULL)
> +		return NULL;
> +
> +	list_for_each_entry(itte, &device->itt, itte_list)
> +		if (itte->event_id == event_id)
> +			return itte;
> +
> +	return NULL;
> +}
> +
>  #define for_each_lpi(dev, itte, kvm) \
>  	list_for_each_entry(dev, &(kvm)->arch.vgic.its.device_list, dev_list) \
>  		list_for_each_entry(itte, &(dev)->itt, itte_list)
> @@ -71,6 +100,19 @@ static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
>  	return NULL;
>  }
>  
> +static struct its_collection *find_collection(struct kvm *kvm, int coll_id)
> +{
> +	struct its_collection *collection;
> +
> +	list_for_each_entry(collection, &kvm->arch.vgic.its.collection_list,
> +			    coll_list) {
> +		if (coll_id == collection->collection_id)
> +			return collection;
> +	}
> +
> +	return NULL;
> +}
> +
>  #define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
>  #define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
>  
> @@ -333,9 +375,461 @@ void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi)
>  	spin_unlock(&its->lock);
>  }
>  
> +static u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
> +{
> +	return (le64_to_cpu(its_cmd[word]) >> shift) & (BIT_ULL(size) - 1);
> +}
> +
> +#define its_cmd_get_command(cmd)	its_cmd_mask_field(cmd, 0,  0,  8)
> +#define its_cmd_get_deviceid(cmd)	its_cmd_mask_field(cmd, 0, 32, 32)
> +#define its_cmd_get_id(cmd)		its_cmd_mask_field(cmd, 1,  0, 32)
> +#define its_cmd_get_physical_id(cmd)	its_cmd_mask_field(cmd, 1, 32, 32)
> +#define its_cmd_get_collection(cmd)	its_cmd_mask_field(cmd, 2,  0, 16)
> +#define its_cmd_get_target_addr(cmd)	its_cmd_mask_field(cmd, 2, 16, 32)
> +#define its_cmd_get_validbit(cmd)	its_cmd_mask_field(cmd, 2, 63,  1)
> +
> +/* The DISCARD command frees an Interrupt Translation Table Entry (ITTE). */
> +static int vits_cmd_handle_discard(struct kvm *kvm, u64 *its_cmd)
> +{
> +	struct vgic_its *its = &kvm->arch.vgic.its;
> +	u32 device_id;
> +	u32 event_id;
> +	struct its_itte *itte;
> +	int ret = 0;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	spin_lock(&its->lock);
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte || !itte->collection) {
> +		ret = E_ITS_DISCARD_UNMAPPED_INTERRUPT;
> +		goto out_unlock;
> +	}
> +
> +	__clear_bit(itte->collection->target_addr, itte->pending);
no use since the itte is deleted afterwards?
> +
> +	list_del(&itte->itte_list);
However what about the deletion of the pending field? May be worth
introducing a function to delete an itte (called several times)
> +	kfree(itte);
> +out_unlock:
> +	spin_unlock(&its->lock);
> +	return ret;
> +}
> +
> +/* The MOVI command moves an ITTE to a different collection. */
> +static int vits_cmd_handle_movi(struct kvm *kvm, u64 *its_cmd)
> +{
> +	struct vgic_its *its = &kvm->arch.vgic.its;
> +	u32 device_id = its_cmd_get_deviceid(its_cmd);
> +	u32 event_id = its_cmd_get_id(its_cmd);
> +	u32 coll_id = its_cmd_get_collection(its_cmd);
> +	struct its_itte *itte;
> +	struct its_collection *collection;
> +	int ret;
> +
> +	spin_lock(&its->lock);
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte) {
> +		ret = E_ITS_MOVI_UNMAPPED_INTERRUPT;
> +		goto out_unlock;
> +	}
> +	if (!itte->collection) {
> +		ret = E_ITS_MOVI_UNMAPPED_COLLECTION;
> +		goto out_unlock;
> +	}
> +
> +	collection = find_collection(kvm, coll_id);
> +	if (!collection) {
> +		ret = E_ITS_MOVI_UNMAPPED_COLLECTION;
> +		goto out_unlock;
> +	}
> +
> +	if (test_and_clear_bit(itte->collection->target_addr, itte->pending))
> +		__set_bit(collection->target_addr, itte->pending);
Don't you think we should make sure target_addr is property set on both
source & destination collection (MAPC with valid bit). Typically the
user could MAPI and then call this. This would encourage to add a valid
bit in the collection struct to tell the target_addr is set.
> +
> +	itte->collection = collection;
> +out_unlock:
> +	spin_unlock(&its->lock);
> +	return ret;
> +}
> +
> +static void vits_init_collection(struct kvm *kvm,
> +				 struct its_collection *collection,
> +				 u32 coll_id)
> +{
> +	collection->collection_id = coll_id;
> +
> +	list_add_tail(&collection->coll_list,
> +		&kvm->arch.vgic.its.collection_list);
> +}
> +
> +/* The MAPTI and MAPI commands map LPIs to ITTEs. */
> +static int vits_cmd_handle_mapi(struct kvm *kvm, u64 *its_cmd, u8 cmd)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	u32 device_id = its_cmd_get_deviceid(its_cmd);
> +	u32 event_id = its_cmd_get_id(its_cmd);
> +	u32 coll_id = its_cmd_get_collection(its_cmd);
> +	struct its_itte *itte, *new_itte;
> +	struct its_device *device;
> +	struct its_collection *collection, *new_coll;
> +	int lpi_nr;
> +	int ret = 0;
> +
> +	/* Preallocate possibly needed memory here outside of the lock */
> +	new_coll = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
> +	new_itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
> +	if (new_itte)
> +		new_itte->pending = kcalloc(BITS_TO_LONGS(dist->nr_cpus),
> +					    sizeof(long), GFP_KERNEL);
> +
> +	spin_lock(&dist->its.lock);
> +
> +	device = find_its_device(kvm, device_id);
> +	if (!device) {
> +		ret = E_ITS_MAPTI_UNMAPPED_DEVICE;
> +		goto out_unlock;
> +	}
> +
> +	collection = find_collection(kvm, coll_id);
> +	if (!collection && !new_coll) {
> +		ret = -ENOMEM;
> +		goto out_unlock;
> +	}
> +
> +	if (cmd == GITS_CMD_MAPTI)
> +		lpi_nr = its_cmd_get_physical_id(its_cmd);
> +	else
> +		lpi_nr = event_id;
> +	if (lpi_nr < GIC_LPI_OFFSET ||
> +	    lpi_nr >= nr_idbits_propbase(dist->propbaser)) {
> +		ret = E_ITS_MAPTI_PHYSICALID_OOR;
> +		goto out_unlock;
> +	}
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte) {
> +		if (!new_itte || !new_itte->pending) {
> +			ret = -ENOMEM;
> +			goto out_unlock;
> +		}
> +		itte = new_itte;
> +
> +		itte->event_id	= event_id;
> +		list_add_tail(&itte->itte_list, &device->itt);
> +	} else {
> +		if (new_itte)
> +			kfree(new_itte->pending);
> +		kfree(new_itte);
> +	}
> +
> +	if (!collection) {
> +		collection = new_coll;
need to handle the case where new_coll is null which would cause a crash
in init_collection
> +		vits_init_collection(kvm, collection, coll_id);
> +	} else {
> +		kfree(new_coll);
> +	}
> +
> +	itte->collection = collection;
> +	itte->lpi = lpi_nr;
> +
> +out_unlock:
> +	spin_unlock(&dist->its.lock);
> +	if (ret) {
> +		kfree(new_coll);
> +		if (new_itte)
> +			kfree(new_itte->pending);
> +		kfree(new_itte);
> +	}
> +	return ret;
> +}
> +
> +static void vits_unmap_device(struct kvm *kvm, struct its_device *device)
> +{
> +	struct its_itte *itte, *temp;
> +
> +	/*
> +	 * The spec says that unmapping a device with still valid
> +	 * ITTEs associated is UNPREDICTABLE. We remove all ITTEs,
> +	 * since we cannot leave the memory unreferenced.
> +	 */
> +	list_for_each_entry_safe(itte, temp, &device->itt, itte_list) {
> +		list_del(&itte->itte_list);
deletion of itte->pending
> +		kfree(itte);
> +	}
> +
> +	list_del(&device->dev_list);
> +	kfree(device);
> +}
> +
> +/* The MAPD command maps device IDs to Interrupt Translation Tables (ITTs). */
or unmaps
> +static int vits_cmd_handle_mapd(struct kvm *kvm, u64 *its_cmd)
> +{
> +	struct vgic_its *its = &kvm->arch.vgic.its;
> +	bool valid = its_cmd_get_validbit(its_cmd);
> +	u32 device_id = its_cmd_get_deviceid(its_cmd);
> +	struct its_device *device, *new_device = NULL;
> +
> +	/* We preallocate memory outside of the lock here */
> +	if (valid) {
> +		new_device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
> +		if (!new_device)
> +			return -ENOMEM;
> +	}
> +
> +	spin_lock(&its->lock);
> +
> +	device = find_its_device(kvm, device_id);
> +	if (device)
logically valid should be false too else that's an error?
> +		vits_unmap_device(kvm, device);
> +
> +	/*
> +	 * The spec does not say whether unmapping a not-mapped device
> +	 * is an error, so we are done in any case.
> +	 */
> +	if (!valid)
> +		goto out_unlock;
> +
> +	device = new_device;
> +
> +	device->device_id = device_id;
> +	INIT_LIST_HEAD(&device->itt);
> +
> +	list_add_tail(&device->dev_list,
> +		      &kvm->arch.vgic.its.device_list);
> +
> +out_unlock:
> +	spin_unlock(&its->lock);
> +	return 0;
> +}
> +
> +/* The MAPC command maps collection IDs to redistributors. */
> +static int vits_cmd_handle_mapc(struct kvm *kvm, u64 *its_cmd)
> +{
> +	struct vgic_its *its = &kvm->arch.vgic.its;
> +	u16 coll_id;
> +	u32 target_addr;
> +	struct its_collection *collection, *new_coll = NULL;
> +	bool valid;
> +
> +	valid = its_cmd_get_validbit(its_cmd);
> +	coll_id = its_cmd_get_collection(its_cmd);
> +	target_addr = its_cmd_get_target_addr(its_cmd);
> +
> +	if (target_addr >= atomic_read(&kvm->online_vcpus))
> +		return E_ITS_MAPC_PROCNUM_OOR;
> +
> +	/* We preallocate memory outside of the lock here */
> +	if (valid) {
> +		new_coll = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
> +		if (!new_coll)
> +			return -ENOMEM;
> +	}
> +
> +	spin_lock(&its->lock);
> +	collection = find_collection(kvm, coll_id);
> +
> +	if (!valid) {
> +		struct its_device *device;
> +		struct its_itte *itte;
> +		/*
> +		 * Clearing the mapping for that collection ID removes the
> +		 * entry from the list. If there wasn't any before, we can
> +		 * go home early.
> +		 */
> +		if (!collection)
> +			goto out_unlock;
> +
> +		for_each_lpi(device, itte, kvm)
> +			if (itte->collection &&
> +			    itte->collection->collection_id == coll_id)
> +				itte->collection = NULL;
> +
> +		list_del(&collection->coll_list);
> +		kfree(collection);
> +	} else {
> +		if (!collection)
> +			collection = new_coll;
> +		else
> +			kfree(new_coll);
> +
> +		vits_init_collection(kvm, collection, coll_id);
> +		collection->target_addr = target_addr;
> +	}
> +
> +out_unlock:
> +	spin_unlock(&its->lock);
> +	return 0;
> +}
> +
> +/* The CLEAR command removes the pending state for a particular LPI. */
> +static int vits_cmd_handle_clear(struct kvm *kvm, u64 *its_cmd)
> +{
> +	struct vgic_its *its = &kvm->arch.vgic.its;
> +	u32 device_id;
> +	u32 event_id;
> +	struct its_itte *itte;
> +	int ret = 0;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	spin_lock(&its->lock);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte) {
> +		ret = E_ITS_CLEAR_UNMAPPED_INTERRUPT;
> +		goto out_unlock;
> +	}
> +
> +	if (itte->collection)
> +		__clear_bit(itte->collection->target_addr, itte->pending);
> +
> +out_unlock:
> +	spin_unlock(&its->lock);
> +	return ret;
> +}
> +
> +/* The INV command syncs the pending bit from the memory tables. */
> +static int vits_cmd_handle_inv(struct kvm *kvm, u64 *its_cmd)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	u32 device_id;
> +	u32 event_id;
> +	struct its_itte *itte, *new_itte;
> +	gpa_t propbase;
> +	int ret;
> +	u8 prop;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	spin_lock(&dist->its.lock);
> +	itte = find_itte(kvm, device_id, event_id);
> +	spin_unlock(&dist->its.lock);
> +	if (!itte)
> +		return E_ITS_INV_UNMAPPED_INTERRUPT;
> +
> +	/*
> +	 * We cannot read from guest memory inside the spinlock, so we
> +	 * need to re-read our tables to learn whether the LPI number we are
> +	 * using is still valid.
> +	 */
> +	do {
> +		propbase = BASER_BASE_ADDRESS(dist->propbaser);
> +		ret = kvm_read_guest(kvm, propbase + itte->lpi - GIC_LPI_OFFSET,
> +				     &prop, 1);
> +		if (ret)
> +			return ret;
> +
> +		spin_lock(&dist->its.lock);
> +		new_itte = find_itte(kvm, device_id, event_id);
> +		if (new_itte->lpi != itte->lpi) {
> +			itte = new_itte;
> +			spin_unlock(&dist->its.lock);
> +			continue;
> +		}
> +		update_lpi_config(kvm, itte, prop);
spec says the pending table should be sync'ed too. shouldn't we update
the pending table in the guest address range?
> +		spin_unlock(&dist->its.lock);
> +	} while (0);
> +	return 0;
> +}
> +
> +/* The INVALL command requests flushing of all IRQ data in this collection. */
> +static int vits_cmd_handle_invall(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u32 coll_id = its_cmd_get_collection(its_cmd);
> +	struct its_collection *collection;
> +	struct kvm_vcpu *vcpu;
> +
> +	collection = find_collection(kvm, coll_id);
> +	if (!collection)
> +		return E_ITS_INVALL_UNMAPPED_COLLECTION;
> +
> +	vcpu = kvm_get_vcpu(kvm, collection->target_addr);
> +
> +	its_update_lpis_configuration(kvm);
> +	its_sync_lpi_pending_table(vcpu);
here we do?
> +
> +	return 0;
> +}
> +
> +/* The MOVALL command moves all IRQs from one redistributor to another. */
> +static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
> +{
> +	struct vgic_its *its = &kvm->arch.vgic.its;
> +	u32 target1_addr = its_cmd_get_target_addr(its_cmd);
> +	u32 target2_addr = its_cmd_mask_field(its_cmd, 3, 16, 32);
> +	struct its_collection *collection;
> +	struct its_device *device;
> +	struct its_itte *itte;
> +
> +	if (target1_addr >= atomic_read(&kvm->online_vcpus) ||
> +	    target2_addr >= atomic_read(&kvm->online_vcpus))
> +		return E_ITS_MOVALL_PROCNUM_OOR;
> +
> +	if (target1_addr == target2_addr)
> +		return 0;
> +
> +	spin_lock(&its->lock);
> +	for_each_lpi(device, itte, kvm) {
> +		/* remap all collections mapped to target address 1 */
> +		collection = itte->collection;
> +		if (collection && collection->target_addr == target1_addr)
> +			collection->target_addr = target2_addr;
> +
> +		/* move pending state if LPI is affected */
> +		if (test_and_clear_bit(target1_addr, itte->pending))
> +			__set_bit(target2_addr, itte->pending);
> +	}
> +
> +	spin_unlock(&its->lock);
> +	return 0;
> +}
> +
>  static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
>  {
> -	return -ENODEV;
> +	u8 cmd = its_cmd_get_command(its_cmd);
> +	int ret = -ENODEV;
> +
> +	switch (cmd) {
> +	case GITS_CMD_MAPD:
> +		ret = vits_cmd_handle_mapd(vcpu->kvm, its_cmd);
> +		break;
> +	case GITS_CMD_MAPC:
> +		ret = vits_cmd_handle_mapc(vcpu->kvm, its_cmd);
> +		break;
> +	case GITS_CMD_MAPI:
> +		ret = vits_cmd_handle_mapi(vcpu->kvm, its_cmd, cmd);
> +		break;
> +	case GITS_CMD_MAPTI:
> +		ret = vits_cmd_handle_mapi(vcpu->kvm, its_cmd, cmd);
> +		break;
> +	case GITS_CMD_MOVI:
> +		ret = vits_cmd_handle_movi(vcpu->kvm, its_cmd);
> +		break;
> +	case GITS_CMD_DISCARD:
> +		ret = vits_cmd_handle_discard(vcpu->kvm, its_cmd);
> +		break;
> +	case GITS_CMD_CLEAR:
> +		ret = vits_cmd_handle_clear(vcpu->kvm, its_cmd);
> +		break;
> +	case GITS_CMD_MOVALL:
> +		ret = vits_cmd_handle_movall(vcpu->kvm, its_cmd);
> +		break;
> +	case GITS_CMD_INV:
> +		ret = vits_cmd_handle_inv(vcpu->kvm, its_cmd);
> +		break;
> +	case GITS_CMD_INVALL:
> +		ret = vits_cmd_handle_invall(vcpu->kvm, its_cmd);
> +		break;
> +	case GITS_CMD_SYNC:
> +		/* we ignore this command: we are in sync all of the time */
> +		ret = 0;
> +		break;
> +	}
> +
> +	return ret;
>  }
>  
>  static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
> @@ -554,6 +1048,7 @@ void vits_destroy(struct kvm *kvm)
>  		list_for_each_safe(cur, temp, &dev->itt) {
>  			itte = (container_of(cur, struct its_itte, itte_list));
>  			list_del(cur);
> +			kfree(itte->pending);
should belong to a previous patch I think

Eric
>  			kfree(itte);
>  		}
>  		list_del(dev_cur);
> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
> index cbc3877..830524a 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -39,4 +39,15 @@ void vits_destroy(struct kvm *kvm);
>  bool vits_queue_lpis(struct kvm_vcpu *vcpu);
>  void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int irq);
>  
> +#define E_ITS_MOVI_UNMAPPED_INTERRUPT		0x010107
> +#define E_ITS_MOVI_UNMAPPED_COLLECTION		0x010109
> +#define E_ITS_CLEAR_UNMAPPED_INTERRUPT		0x010507
> +#define E_ITS_MAPC_PROCNUM_OOR			0x010902
> +#define E_ITS_MAPTI_UNMAPPED_DEVICE		0x010a04
> +#define E_ITS_MAPTI_PHYSICALID_OOR		0x010a06
> +#define E_ITS_INV_UNMAPPED_INTERRUPT		0x010c07
> +#define E_ITS_INVALL_UNMAPPED_COLLECTION	0x010d09
> +#define E_ITS_MOVALL_PROCNUM_OOR		0x010e01
> +#define E_ITS_DISCARD_UNMAPPED_INTERRUPT	0x010f07
> +
>  #endif
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation
  2015-07-10 14:21 ` [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation Andre Przywara
  2015-07-31 13:22   ` Eric Auger
@ 2015-08-17 13:44   ` Eric Auger
  1 sibling, 0 replies; 69+ messages in thread
From: Eric Auger @ 2015-08-17 13:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/10/2015 04:21 PM, Andre Przywara wrote:
> When userland wants to inject a MSI into the guest, we have to use
> our data structures to find the LPI number and the VCPU to receive
> the interrupt.
> Use the wrapper functions to iterate the linked lists and find the
> proper Interrupt Translation Table Entry. Then set the pending bit
> in this ITTE to be later picked up by the LR handling code. Kick
> the VCPU which is meant to handle this interrupt.
> We provide a VGIC emulation model specific routine for the actual
> MSI injection. The wrapper functions return an error for models not
> (yet) implementing MSIs (like the GICv2 emulation).
> We also provide the handler for the ITS "INT" command, which allows a
> guest to trigger an MSI via the ITS command queue.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h      |  1 +
>  virt/kvm/arm/its-emul.c     | 65 +++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h     |  2 ++
>  virt/kvm/arm/vgic-v3-emul.c |  1 +
>  4 files changed, 69 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 323c33a..9e1abf9 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -149,6 +149,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);
> +	int	(*inject_msi)(struct kvm *, struct kvm_msi *);
>  };
>  
>  struct vgic_io_device {
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index 89534c6..a1c12bb 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -323,6 +323,55 @@ static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
>  }
>  
>  /*
> + * Translates an incoming MSI request into the redistributor (=VCPU) and
> + * the associated LPI number. Sets the LPI pending bit and also marks the
> + * VCPU as having a pending interrupt.
> + */
> +int vits_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct vgic_its *its = &dist->its;
> +	struct its_itte *itte;
> +	int cpuid;
> +	bool inject = false;
> +	int ret = 0;
> +
> +	if (!vgic_has_its(kvm))
> +		return -ENODEV;
> +
> +	if (!(msi->flags & KVM_MSI_VALID_DEVID))
> +		return -EINVAL;
> +
> +	spin_lock(&its->lock);
> +
> +	if (!its->enabled || !dist->lpis_enabled) {
> +		ret = -EAGAIN;
> +		goto out_unlock;
> +	}
> +
> +	itte = find_itte(kvm, msi->devid, msi->data);
> +	/* Triggering an unmapped IRQ gets silently dropped. */
> +	if (!itte || !itte->collection)
> +		goto out_unlock;
> +
> +	cpuid = itte->collection->target_addr;
what if MAPC was not done?
> +	__set_bit(cpuid, itte->pending);
> +	inject = itte->enabled;
> +
> +out_unlock:
> +	spin_unlock(&its->lock);
> +
> +	if (inject) {
> +		spin_lock(&dist->lock);
deadlock when called from vits_handle_command?

Eric
> +		__set_bit(cpuid, dist->irq_pending_on_cpu);
> +		spin_unlock(&dist->lock);
> +		kvm_vcpu_kick(kvm_get_vcpu(kvm, cpuid));
> +	}
> +
> +	return ret;
> +}
> +
> +/*
>   * Find all enabled and pending LPIs and queue them into the list
>   * registers.
>   * The dist lock is held by the caller.
> @@ -787,6 +836,19 @@ static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
>  	return 0;
>  }
>  
> +/* The INT command injects the LPI associated with that DevID/EvID pair. */
> +static int vits_cmd_handle_int(struct kvm *kvm, u64 *its_cmd)
> +{
> +	struct kvm_msi msi = {
> +		.data = its_cmd_get_id(its_cmd),
> +		.devid = its_cmd_get_deviceid(its_cmd),
> +		.flags = KVM_MSI_VALID_DEVID,
> +	};
> +
> +	vits_inject_msi(kvm, &msi);
> +	return 0;
> +}
> +
>  static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
>  {
>  	u8 cmd = its_cmd_get_command(its_cmd);
> @@ -817,6 +879,9 @@ static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
>  	case GITS_CMD_MOVALL:
>  		ret = vits_cmd_handle_movall(vcpu->kvm, its_cmd);
>  		break;
> +	case GITS_CMD_INT:
> +		ret = vits_cmd_handle_int(vcpu->kvm, its_cmd);
> +		break;
>  	case GITS_CMD_INV:
>  		ret = vits_cmd_handle_inv(vcpu->kvm, its_cmd);
>  		break;
> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
> index 830524a..95e56a7 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -36,6 +36,8 @@ void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>  int vits_init(struct kvm *kvm);
>  void vits_destroy(struct kvm *kvm);
>  
> +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);
>  
> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
> index 4132c26..30bf7035 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -948,6 +948,7 @@ void vgic_v3_init_emulation(struct kvm *kvm)
>  	dist->vm_ops.init_model = vgic_v3_init_model;
>  	dist->vm_ops.destroy_model = vgic_v3_destroy_model;
>  	dist->vm_ops.map_resources = vgic_v3_map_resources;
> +	dist->vm_ops.inject_msi = vits_inject_msi;
>  	dist->vm_ops.queue_lpis = vits_queue_lpis;
>  	dist->vm_ops.unqueue_lpi = vits_unqueue_lpi;
>  
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation
  2015-08-03 17:06               ` Marc Zyngier
  2015-08-04  6:53                 ` Pavel Fedin
@ 2015-08-24 14:14                 ` Andre Przywara
  1 sibling, 0 replies; 69+ messages in thread
From: Andre Przywara @ 2015-08-24 14:14 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 03/08/15 18:06, Marc Zyngier wrote:
> On 03/08/15 16:37, Eric Auger wrote:
>> Andre, Pavel,
>> On 08/03/2015 11:16 AM, Pavel Fedin wrote:
>>>  Hello!
>>>
>>>> Again the case that leaves me uncomfortable is the one where the
>>>> userspace does not provide the devid whereas it must (GICv3 ITS case).
>>>
>>>  Hypothetical broken userland which does not exist for now ?
>> Yes but that's the rule to be not confident in *any* userspace, isn't it?

Well, that's only regarding safety, not regarding functionality, right?
So if we could break the kernel by not providing the flag and/or devid,
this needs to be fixed. But if it just doesn't work, that's OK.

>>
>> As of now I prefer keeping the flags at uapi level and propagate it
>> downto the kernel, as long as I don't have any answer for the unset
>> devid discrimination question. Please apologize for my stubbornness ;-)
> 
> I think this flag should be kept, as it really indicates what is valid
> in the MSI structure. It also has other benefits such as making obvious
> what userspace expects, which can then be checked against the kernel's
> own expectations.

I agree on this. Usually this kind of redundancy leads to strange code,
but this does not seem to apply here, since we can at least still guard
the assignments to demonstrate that the devid field needs to go along
with the flag.

Cheers,
Andre.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-08-12  9:01   ` Eric Auger
@ 2015-08-24 16:33     ` Andre Przywara
  2015-08-31  8:42       ` Eric Auger
  0 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-08-24 16:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

On 12/08/15 10:01, Eric Auger wrote:
....
>> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
>> index bc40137..394622c 100644
>> --- a/virt/kvm/arm/vgic.c
>> +++ b/virt/kvm/arm/vgic.c
>> @@ -79,7 +79,6 @@
>>  #include "vgic.h"
>>  
>>  static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu);
>> -static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu);
>>  static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr);
>>  static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr, struct vgic_lr lr_desc);
>>  
>> @@ -647,6 +646,17 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
>>  	return false;
>>  }
>>  
>> +static void vgic_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
>> +			       struct vgic_lr vlr)
>> +{
>> +	vgic_ops->sync_lr_elrsr(vcpu, lr, vlr);
>> +}
> why not renaming this into vgic_set_elrsr. This would be homogeneous
> with other virtual interface control register setters?

But that would involve renaming the vgic_ops members as well to be
consistent, right? As there is no change in the behaviour, a naming
change sounds unmotivated to me. And _set_ wouldn't be exact, as this
function deals only with only one bit at a time and allows to clear it
as well.

>> +
>> +static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
>> +{
>> +	return vgic_ops->get_elrsr(vcpu);
>> +}
> If I am not wrong, each time you manipulate the elrsr you handle the
> bitmap. why not directly returning an unsigned long * then (elrsr_ptr)?

Because the pointer needs to point somewhere, and that storage is
currently located on the caller's stack. Directly returning a pointer
would require the caller to provide some memory for the u64, which does
not save you so much in terms on LOC:

-	u64 elrsr = vgic_get_elrsr(vcpu);
-	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
+	u64 elrsr;
+	unsigned long *elrsr_ptr = vgic_get_elrsr_bm(vcpu, &elrsr);

Also we need u64_to_bitmask() in one case when converting the EISR
value, so we cannot get lost of that function.

>> +
>>  /**
>>   * vgic_unqueue_irqs - move pending/active IRQs from LRs to the distributor
>>   * @vgic_cpu: Pointer to the vgic_cpu struct holding the LRs
>> @@ -658,9 +668,11 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
>>  void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
>>  {
>>  	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	u64 elrsr = vgic_get_elrsr(vcpu);
>> +	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
>>  	int i;
>>  
>> -	for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) {
>> +	for_each_clear_bit(i, elrsr_ptr, vgic_cpu->nr_lr) {
>>  		struct vgic_lr lr = vgic_get_lr(vcpu, i);
>>  
>>  		/*
>> @@ -703,7 +715,7 @@ void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
>>  		 * Mark the LR as free for other use.
>>  		 */
>>  		BUG_ON(lr.state & LR_STATE_MASK);
>> -		vgic_retire_lr(i, lr.irq, vcpu);
>> +		vgic_sync_lr_elrsr(vcpu, i, lr);
>>  		vgic_irq_clear_queued(vcpu, lr.irq);
>>  
>>  		/* Finally update the VGIC state. */
>> @@ -1011,17 +1023,6 @@ static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr,
>>  	vgic_ops->set_lr(vcpu, lr, vlr);
>>  }
>>  
>> -static void vgic_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
>> -			       struct vgic_lr vlr)
>> -{
>> -	vgic_ops->sync_lr_elrsr(vcpu, lr, vlr);
>> -}
>> -
>> -static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
>> -{
>> -	return vgic_ops->get_elrsr(vcpu);
>> -}
>> -
>>  static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
>>  {
>>  	return vgic_ops->get_eisr(vcpu);
>> @@ -1062,18 +1063,6 @@ static inline void vgic_enable(struct kvm_vcpu *vcpu)
>>  	vgic_ops->enable(vcpu);
>>  }
>>  
>> -static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
>> -{
>> -	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> -	struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr);
>> -
>> -	vlr.state = 0;
>> -	vgic_set_lr(vcpu, lr_nr, vlr);
>> -	clear_bit(lr_nr, vgic_cpu->lr_used);
>> -	vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
>> -	vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
>> -}
>> -
>>  /*
>>   * An interrupt may have been disabled after being made pending on the
>>   * CPU interface (the classic case is a timer running while we're
>> @@ -1085,23 +1074,32 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
>>   */
>>  static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
>>  {
>> -	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	u64 elrsr = vgic_get_elrsr(vcpu);
>> +	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
> if you agree with above modif I would simply rename elrsr_ptr into elrsr.
>>  	int lr;
>> +	struct vgic_lr vlr;
> why moving this declaration here. I think this can remain in the block.

Possibly. Don't remember the reason of this move, I think it was due to
some other changes I later removed. I will revert it.

>>  
>> -	for_each_set_bit(lr, vgic_cpu->lr_used, vgic->nr_lr) {
>> -		struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
>> +	for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) {
>> +		vlr = vgic_get_lr(vcpu, lr);
>>  
>>  		if (!vgic_irq_is_enabled(vcpu, vlr.irq)) {
>> -			vgic_retire_lr(lr, vlr.irq, vcpu);
>> -			if (vgic_irq_is_queued(vcpu, vlr.irq))
>> -				vgic_irq_clear_queued(vcpu, vlr.irq);
>> +			vlr.state = 0;
>> +			vgic_set_lr(vcpu, lr, vlr);
>> +			vgic_sync_lr_elrsr(vcpu, lr, vlr);
> vgic_set_elrsr?
> 
> the "if (vgic_irq_is_queued(vcpu, vlr.irq))" check disappeared. This
> change might be introduced separately.

OK, this is an admittedly independent optimization to avoid the needless
check for "clear only set bits". I didn't find it useful to spin a
separate patch for this, so just fixed this while reworking this code
anyway.

>> +			vgic_irq_clear_queued(vcpu, vlr.irq);
>>  		}
>>  	}
>>  }
>>  
>>  static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>> -				 int lr_nr, struct vgic_lr vlr)
> I don't think this change of proto is compatible with Marc's "KVM:
> arm/arm64: vgic: Allow HW interrupts to be queued to a guest".
> I think we need to keep former signature.

I will need to rebase my series on top of the 4.3 pull request anyway,
so: yes, I will adapt to Marc's series.

>> +				 int lr_nr, int sgi_source_id)
>>  {
>> +	struct vgic_lr vlr;
>> +
>> +	vlr.state = 0;
>> +	vlr.irq = irq;
>> +	vlr.source = sgi_source_id;
>> +
>>  	if (vgic_irq_is_active(vcpu, irq)) {
>>  		vlr.state |= LR_STATE_ACTIVE;
>>  		kvm_debug("Set active, clear distributor: 0x%x\n", vlr.state);
>> @@ -1126,9 +1124,9 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>>   */
>>  bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>>  {
>> -	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>  	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>> -	struct vgic_lr vlr;
>> +	u64 elrsr = vgic_get_elrsr(vcpu);
>> +	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
>>  	int lr;
>>  
>>  	/* Sanitize the input... */
>> @@ -1138,42 +1136,20 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>>  
>>  	kvm_debug("Queue IRQ%d\n", irq);
>>  
>> -	lr = vgic_cpu->vgic_irq_lr_map[irq];
>> -
>> -	/* Do we have an active interrupt for the same CPUID? */
>> -	if (lr != LR_EMPTY) {
>> -		vlr = vgic_get_lr(vcpu, lr);
>> -		if (vlr.source == sgi_source_id) {
>> -			kvm_debug("LR%d piggyback for IRQ%d\n", lr, vlr.irq);
>> -			BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
>> -			vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
>> -			return true;
>> -		}
>> -	}
>> +	lr = find_first_bit(elrsr_ptr, vgic->nr_lr);
>>  
>> -	/* Try to use another LR for this interrupt */
>> -	lr = find_first_zero_bit((unsigned long *)vgic_cpu->lr_used,
>> -			       vgic->nr_lr);
>>  	if (lr >= vgic->nr_lr)
>>  		return false;
>>  
>>  	kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id);
>> -	vgic_cpu->vgic_irq_lr_map[irq] = lr;
>> -	set_bit(lr, vgic_cpu->lr_used);
>>  
>> -	vlr.irq = irq;
>> -	vlr.source = sgi_source_id;
>> -	vlr.state = 0;
>> -	vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
>> +	vgic_queue_irq_to_lr(vcpu, irq, lr, sgi_source_id);
>>  
>>  	return true;
>>  }
>>  
>>  static bool vgic_queue_hwirq(struct kvm_vcpu *vcpu, int irq)
>>  {
>> -	if (!vgic_can_sample_irq(vcpu, irq))
>> -		return true; /* level interrupt, already queued */
>> -
> I think that change needs to be introduced in a separate patch as the
> other one mentioned above and justified since it affects the state machine.

But this change is dependent on this patch: it will not work without
this patch and this patch will not work without that change.
So the idea is that on returning from the guest we now harvest all
_used_ LRs by copying their state back into the distributor. The
previous behaviour was to just check _unused_ LRs for completed IRQs.
So now all IRQs need to be re-inserted into the LRs before the next
guest run, that's why we have to remove the test which skipped this for
IRQs where the code knew that they were still in the LRs.
Does that make sense?

Cheers,
Andre.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 05/15] KVM: arm/arm64: make GIC frame address initialization model specific
  2015-08-12 13:02   ` Eric Auger
@ 2015-08-24 17:24     ` Andre Przywara
  2015-08-31  9:31       ` Eric Auger
  0 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-08-24 17:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/08/15 14:02, Eric Auger wrote:
> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>> Currently we initialize all the possible GIC frame addresses in one
>> function, without looking at the specific GIC model we instantiate
>> for the guest.
>> As this gets confusing when adding another VGIC model later, lets
>> move these initializations into the respective model's init 
> nit: tobe more precise the init emulation function (not the
> vgic_v2/v3_init_model model's init function). pfouh?! ;-)
> functions.

OK, will try to find a wording that is not completely confusing.

>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic-v2-emul.c | 3 +++
>>  virt/kvm/arm/vgic-v3-emul.c | 3 +++
>>  virt/kvm/arm/vgic.c         | 3 ---
>>  3 files changed, 6 insertions(+), 3 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c
>> index 1390797..8faa28c 100644
>> --- a/virt/kvm/arm/vgic-v2-emul.c
>> +++ b/virt/kvm/arm/vgic-v2-emul.c
>> @@ -567,6 +567,9 @@ void vgic_v2_init_emulation(struct kvm *kvm)
>>  	dist->vm_ops.init_model = vgic_v2_init_model;
>>  	dist->vm_ops.map_resources = vgic_v2_map_resources;
>>  
>> +	dist->vgic_cpu_base = VGIC_ADDR_UNDEF;
>> +	dist->vgic_dist_base = VGIC_ADDR_UNDEF;
> Looks strange to see the common dist_base here. Why don't you leave it
> in common part, kvm_vgic_create; all the more so you left
> kvm->arch.vgic.vctrl_base = vgic->vctrl_base in kvm_vgic_create.

The idea behind this is that dist_base refers to similar, but not
identical distributors (v2 vs. v3), so I found it a good idea to
initialize it in here. Also vctrl_base is host facing and not set by
userland, so this doesn't really compare here.

Cheers,
Andre.

>> +
>>  	kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
>>  }
>>  
>> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
>> index d2eeb20..1f42348 100644
>> --- a/virt/kvm/arm/vgic-v3-emul.c
>> +++ b/virt/kvm/arm/vgic-v3-emul.c
>> @@ -885,6 +885,9 @@ void vgic_v3_init_emulation(struct kvm *kvm)
>>  	dist->vm_ops.destroy_model = vgic_v3_destroy_model;
>>  	dist->vm_ops.map_resources = vgic_v3_map_resources;
>>  
>> +	dist->vgic_dist_base = VGIC_ADDR_UNDEF;
>> +	dist->vgic_redist_base = VGIC_ADDR_UNDEF;
>> +
>>  	kvm->arch.max_vcpus = KVM_MAX_VCPUS;
>>  }
>>  
>> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
>> index cc8f5ed..59f1801 100644
>> --- a/virt/kvm/arm/vgic.c
>> +++ b/virt/kvm/arm/vgic.c
>> @@ -1830,9 +1830,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
>>  	kvm->arch.vgic.in_kernel = true;
>>  	kvm->arch.vgic.vgic_model = type;
>>  	kvm->arch.vgic.vctrl_base = vgic->vctrl_base;
>> -	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
>> -	kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
>> -	kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
>>  
>>  out_unlock:
>>  	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
>>
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 07/15] KVM: arm64: handle ITS related GICv3 redistributor registers
  2015-08-13 12:17   ` Eric Auger
@ 2015-08-24 18:08     ` Andre Przywara
  0 siblings, 0 replies; 69+ messages in thread
From: Andre Przywara @ 2015-08-24 18:08 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

On 13/08/15 13:17, Eric Auger wrote:
> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>> In the GICv3 redistributor there are the PENDBASER and PROPBASER
>> registers which we did not emulate so far, as they only make sense
>> when having an ITS. In preparation for that emulate those MMIO
>> accesses by storing the 64-bit data written into it into a variable
>> which we later read in the ITS emulation.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/arm_vgic.h      |  8 ++++++++
>>  virt/kvm/arm/vgic-v3-emul.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic.c         | 35 +++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic.h         |  4 ++++
>>  4 files changed, 91 insertions(+)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 3ee063b..8c6cb0e 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -256,6 +256,14 @@ struct vgic_dist {
>>  	struct vgic_vm_ops	vm_ops;
>>  	struct vgic_io_device	dist_iodev;
>>  	struct vgic_io_device	*redist_iodevs;
>> +
>> +	/* Address of LPI configuration table shared by all redistributors */
>> +	u64			propbaser;
>> +
>> +	/* Addresses of LPI pending tables per redistributor */
>> +	u64			*pendbaser;
>> +
>> +	bool			lpis_enabled;
>>  };
>>  
>>  struct vgic_v2_cpu_if {
>> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
>> index a8cf669..5269ad1 100644
>> --- a/virt/kvm/arm/vgic-v3-emul.c
>> +++ b/virt/kvm/arm/vgic-v3-emul.c
>> @@ -651,6 +651,38 @@ static bool handle_mmio_cfg_reg_redist(struct kvm_vcpu *vcpu,
>>  	return vgic_handle_cfg_reg(reg, mmio, offset);
>>  }
>>  
>> +/* We don't trigger any actions here, just store the register value */
>> +static bool handle_mmio_propbaser_redist(struct kvm_vcpu *vcpu,
>> +					 struct kvm_exit_mmio *mmio,
>> +					 phys_addr_t offset)
>> +{
>> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>> +	int mode = ACCESS_READ_VALUE;
>> +
>> +	/* Storing a value with LPIs already enabled is undefined */
>> +	mode |= dist->lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
>> +	vgic_handle_base_register(vcpu, mmio, offset, &dist->propbaser, mode);
>> +
>> +	return false;
>> +}
>> +
>> +/* We don't trigger any actions here, just store the register value */
>> +static bool handle_mmio_pendbaser_redist(struct kvm_vcpu *vcpu,
>> +					 struct kvm_exit_mmio *mmio,
>> +					 phys_addr_t offset)
>> +{
>> +	struct kvm_vcpu *rdvcpu = mmio->private;
>> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>> +	int mode = ACCESS_READ_VALUE;
>> +
>> +	/* Storing a value with LPIs already enabled is undefined */
>> +	mode |= dist->lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
>> +	vgic_handle_base_register(vcpu, mmio, offset,
>> +				  &dist->pendbaser[rdvcpu->vcpu_id], mode);
>> +
>> +	return false;
>> +}
>> +
>>  #define SGI_base(x) ((x) + SZ_64K)
>>  
>>  static const struct vgic_io_range vgic_redist_ranges[] = {
>> @@ -679,6 +711,18 @@ static const struct vgic_io_range vgic_redist_ranges[] = {
>>  		.handle_mmio    = handle_mmio_raz_wi,
>>  	},
>>  	{
>> +		.base		= GICR_PENDBASER,
>> +		.len		= 0x08,
>> +		.bits_per_irq	= 0,
>> +		.handle_mmio	= handle_mmio_pendbaser_redist,
>> +	},
>> +	{
>> +		.base		= GICR_PROPBASER,
>> +		.len		= 0x08,
>> +		.bits_per_irq	= 0,
>> +		.handle_mmio	= handle_mmio_propbaser_redist,
>> +	},
>> +	{
>>  		.base           = GICR_IDREGS,
>>  		.len            = 0x30,
>>  		.bits_per_irq   = 0,
>> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
>> index 15e447f..49ee92b 100644
>> --- a/virt/kvm/arm/vgic.c
>> +++ b/virt/kvm/arm/vgic.c
>> @@ -446,6 +446,41 @@ void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
>>  	}
>>  }
>>  
>> +/* handle a 64-bit register access */
>> +void vgic_handle_base_register(struct kvm_vcpu *vcpu,
>> +			       struct kvm_exit_mmio *mmio,
>> +			       phys_addr_t offset, u64 *basereg,
>> +			       int mode)
>> +{
> why do we have vcpu in the proto? I don't see it used. Also if it were
> can't we fetch it from mmio->private?
> 
> why not renaming this into something like vgic_reg64_access as par
> vgic_reg_access 32b flavor above. vgic_handle* usually is the name of
> the region handler returning bool?

Makes sense, I both renamed the function and removed the vcpu parameter.
I need to check whether we need the vcpu to do some endianness checks in
the future, though. Using mmio->private would be a hack, then.

Cheers,
Andre.

> 
>> +	u32 reg;
>> +	u64 breg;
>> +
>> +	switch (offset & ~3) {
>> +	case 0x00:
>> +		breg = *basereg;
>> +		reg = lower_32_bits(breg);
>> +		vgic_reg_access(mmio, &reg, offset & 3, mode);
>> +		if (mmio->is_write && (mode & ACCESS_WRITE_VALUE)) {
>> +			breg &= GENMASK_ULL(63, 32);
>> +			breg |= reg;
>> +			*basereg = breg;
>> +		}
>> +		break;
>> +	case 0x04:
>> +		breg = *basereg;
>> +		reg = upper_32_bits(breg);
>> +		vgic_reg_access(mmio, &reg, offset & 3, mode);
>> +		if (mmio->is_write && (mode & ACCESS_WRITE_VALUE)) {
>> +			breg  = lower_32_bits(breg);
>> +			breg |= (u64)reg << 32;
>> +			*basereg = breg;
>> +		}
>> +		break;
>> +	}
>> +}
>> +
>> +
>> +
> some spare white lines
> 
> Best Regards
> 
> Eric
>>  bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
>>  			phys_addr_t offset)
>>  {
>> diff --git a/virt/kvm/arm/vgic.h b/virt/kvm/arm/vgic.h
>> index a093f5c..b2d791c 100644
>> --- a/virt/kvm/arm/vgic.h
>> +++ b/virt/kvm/arm/vgic.h
>> @@ -71,6 +71,10 @@ void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
>>  		     phys_addr_t offset, int mode);
>>  bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
>>  			phys_addr_t offset);
>> +void vgic_handle_base_register(struct kvm_vcpu *vcpu,
>> +			       struct kvm_exit_mmio *mmio,
>> +			       phys_addr_t offset, u64 *basereg,
>> +			       int mode);
>>  
>>  static inline
>>  u32 mmio_data_read(struct kvm_exit_mmio *mmio, u32 mask)
>>
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 08/15] KVM: arm64: introduce ITS emulation file with stub functions
  2015-08-13 12:48   ` Eric Auger
@ 2015-08-25  9:39     ` Andre Przywara
  0 siblings, 0 replies; 69+ messages in thread
From: Andre Przywara @ 2015-08-25  9:39 UTC (permalink / raw)
  To: linux-arm-kernel

Salut Eric,

....

>> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
>> index 5269ad1..f5865e7 100644
>> --- a/virt/kvm/arm/vgic-v3-emul.c
>> +++ b/virt/kvm/arm/vgic-v3-emul.c
>> @@ -48,6 +48,7 @@
>>  #include <asm/kvm_mmu.h>
>>  
>>  #include "vgic.h"
>> +#include "its-emul.h"
>>  
>>  static bool handle_mmio_rao_wi(struct kvm_vcpu *vcpu,
>>  			       struct kvm_exit_mmio *mmio, phys_addr_t offset)
>> @@ -530,9 +531,20 @@ static bool handle_mmio_ctlr_redist(struct kvm_vcpu *vcpu,
>>  				    struct kvm_exit_mmio *mmio,
>>  				    phys_addr_t offset)
>>  {
>> -	/* since we don't support LPIs, this register is zero for now */
>> -	vgic_reg_access(mmio, NULL, offset,
>> -			ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
>> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>> +	u32 reg;
>> +
>> +	if (!vgic_has_its(vcpu->kvm)) {
>> +		vgic_reg_access(mmio, NULL, offset,
>> +				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
>> +		return false;
>> +	}
> can't we remove above block and ...
>> +	reg = dist->lpis_enabled ? GICR_CTLR_ENABLE_LPIS : 0;
>> +	vgic_reg_access(mmio, &reg, offset,
>> +			ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
>> +	if (!dist->lpis_enabled && (reg & GICR_CTLR_ENABLE_LPIS
> add vgic_has_its(vcpu->kvm) && above?

Yeah, makes some sense. Changed that.
> 
> Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>

Merci!

Andr?

> 
> Eric
> )) {
>> +		/* Eventually do something */
>> +	}
>>  	return false;
>>  }
>>  
>> @@ -861,6 +873,12 @@ static int vgic_v3_map_resources(struct kvm *kvm,
>>  		rdbase += GIC_V3_REDIST_SIZE;
>>  	}
>>  
>> +	if (vgic_has_its(kvm)) {
>> +		ret = vits_init(kvm);
>> +		if (ret)
>> +			goto out_unregister;
>> +	}
>> +
>>  	dist->redist_iodevs = iodevs;
>>  	dist->ready = true;
>>  	goto out;
>>
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 09/15] KVM: arm64: implement basic ITS register handlers
  2015-08-13 15:25   ` Eric Auger
@ 2015-08-25 10:23     ` Andre Przywara
  0 siblings, 0 replies; 69+ messages in thread
From: Andre Przywara @ 2015-08-25 10:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

....

>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>> index 659dd39..b498f06 100644
>> --- a/virt/kvm/arm/its-emul.c
>> +++ b/virt/kvm/arm/its-emul.c
>> @@ -32,10 +32,62 @@
>>  #include "vgic.h"
>>  #include "its-emul.h"
>>
>> +#define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>> +
>> +/* The distributor lock is held by the VGIC MMIO handler. */
>>  static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
>>                                 struct kvm_exit_mmio *mmio,
>>                                 phys_addr_t offset)
>>  {
>> +     struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
>> +     u32 reg;
>> +     bool was_enabled;
>> +
>> +     switch (offset & ~3) {
>> +     case 0x00:              /* GITS_CTLR */
>> +             /* We never defer any command execution. */
>> +             reg = GITS_CTLR_QUIESCENT;
>> +             if (its->enabled)
>> +                     reg |= GITS_CTLR_ENABLE;
>> +             was_enabled = its->enabled;
>> +             vgic_reg_access(mmio, &reg, offset & 3,
>> +                             ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
>> +             its->enabled = !!(reg & GITS_CTLR_ENABLE);
>> +             return !was_enabled && its->enabled;
>> +     case 0x04:              /* GITS_IIDR */
>> +             reg = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>> +             vgic_reg_access(mmio, &reg, offset & 3,
>> +                             ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
>> +             break;
>> +     case 0x08:              /* GITS_TYPER */
>> +             /*
>> +              * We use linear CPU numbers for redistributor addressing,
>> +              * so GITS_TYPER.PTA is 0.
>> +              * To avoid memory waste on the guest side, we keep the
>> +              * number of IDBits and DevBits low for the time being.
>> +              * This could later be made configurable by userland.
>> +              * Since we have all collections in linked list, we claim
>> +              * that we can hold all of the collection tables in our
>> +              * own memory and that the ITT entry size is 1 byte (the
>> +              * smallest possible one).
>> +              */
>> +             reg = GITS_TYPER_PLPIS;
>> +             reg |= 0xff << GITS_TYPER_HWCOLLCNT_SHIFT;
>> +             reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT;
>> +             reg |= 0x0f << GITS_TYPER_IDBITS_SHIFT;
>> +             vgic_reg_access(mmio, &reg, offset & 3,
>> +                             ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
>> +             break;
>> +     case 0x0c:
>> +             /* The upper 32bits of TYPER are all 0 for the time being.
>> +              * Should we need more than 256 collections, we can enable
>> +              * some bits in here.
>> +              */
>> +             vgic_reg_access(mmio, NULL, offset & 3,
>> +                             ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
>> +             break;
>> +     }
>> +
>>       return false;
>>  }
>>
>> @@ -43,20 +95,142 @@ static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
>>                                   struct kvm_exit_mmio *mmio,
>>                                   phys_addr_t offset)
>>  {
>> +     u32 reg = 0;
>> +     int idreg = (offset & ~3) + GITS_IDREGS_BASE;
>> +
>> +     switch (idreg) {
>> +     case GITS_PIDR2:
>> +             reg = GIC_PIDR2_ARCH_GICv3;
>> +             break;
>> +     case GITS_PIDR4:
>> +             /* This is a 64K software visible page */
>> +             reg = 0x40;
>> +             break;
>> +     /* Those are the ID registers for (any) GIC. */
>> +     case GITS_CIDR0:
>> +             reg = 0x0d;
>> +             break;
>> +     case GITS_CIDR1:
>> +             reg = 0xf0;
>> +             break;
>> +     case GITS_CIDR2:
>> +             reg = 0x05;
>> +             break;
>> +     case GITS_CIDR3:
>> +             reg = 0xb1;
>> +             break;
>> +     }
>> +     vgic_reg_access(mmio, &reg, offset & 3,
>> +                     ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
>>       return false;
>>  }
>>
>> +static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
>> +{
>> +     return -ENODEV;
>> +}
>> +
>>  static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
>>                                   struct kvm_exit_mmio *mmio,
>>                                   phys_addr_t offset)
>>  {
>> +     struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
>> +     int mode = ACCESS_READ_VALUE;
>> +
>> +     mode |= its->enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
>> +
>> +     vgic_handle_base_register(vcpu, mmio, offset, &its->cbaser, mode);
>> +
>> +     /* Writing CBASER resets the read pointer. */
>> +     if (mmio->is_write)
>> +             its->creadr = 0;
>> +
>>       return false;
>>  }
>>
>> +static int its_cmd_buffer_size(struct kvm *kvm)
>> +{
>> +     struct vgic_its *its = &kvm->arch.vgic.its;
>> +
>> +     return ((its->cbaser & 0xff) + 1) << 12;
>> +}
>> +
>> +static gpa_t its_cmd_buffer_base(struct kvm *kvm)
>> +{
>> +     struct vgic_its *its = &kvm->arch.vgic.its;
>> +
>> +     return BASER_BASE_ADDRESS(its->cbaser);
>> +}
>> +
>> +/*
>> + * By writing to CWRITER the guest announces new commands to be processed.
>> + * Since we cannot read from guest memory inside the ITS spinlock, we
>> + * iterate over the command buffer (with the lock dropped) until the read
>> + * pointer matches the write pointer. Other VCPUs writing this register in the
>> + * meantime will just update the write pointer, leaving the command
>> + * processing to the first instance of the function.
>> + */
> I am lost, isn't the dist lock hold by vgic_handle_mmio_access before
> calling call_range_handler/range->handle_mmio ?

Indeed, I was so focussed on the ITS lock...

> if confirmed we need to move the command enumeration + execution
> somewhere else.

I think we get away with dropping the dist lock after doing the actual
register access. Just before returning we then take it again to make the
caller happy.
I will give this a try. Thanks for spotting this!

> Besides that piece of code may deserve to be
> encaspulated in a function. what do you think?

Makes some sense, yes.

Cheers,
Andr?

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 10/15] KVM: arm64: add data structures to model ITS interrupt translation
  2015-08-13 15:46   ` Eric Auger
@ 2015-08-25 11:15     ` Andre Przywara
  2015-08-27 14:16       ` Eric Auger
  0 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-08-25 11:15 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

On 13/08/15 16:46, Eric Auger wrote:
> 
> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>> The GICv3 Interrupt Translation Service (ITS) uses tables in memory
>> to allow a sophisticated interrupt routing. It features device tables,
>> an interrupt table per device and a table connecting "collections" to
>> actual CPUs (aka. redistributors in the GICv3 lingo).
>> Since the interrupt numbers for the LPIs are allocated quite sparsely
>> and the range can be quite huge (8192 LPIs being the minimum), using
>> bitmaps or arrays for storing information is a waste of memory.
>> We use linked lists instead, which we iterate linearily. This works
>> very well with the actual number of LPIs/MSIs in the guest being
>> quite low. Should the number of LPIs exceed the number where iterating
>> through lists seems acceptable, we can later revisit this and use more
>> efficient data structures.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/arm_vgic.h  |  3 +++
>>  virt/kvm/arm/its-emul.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 51 insertions(+)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index b432055..1648668 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -25,6 +25,7 @@
>>  #include <linux/spinlock.h>
>>  #include <linux/types.h>
>>  #include <kvm/iodev.h>
>> +#include <linux/list.h>
>>  
>>  #define VGIC_NR_IRQS_LEGACY	256
>>  #define VGIC_NR_SGIS		16
>> @@ -162,6 +163,8 @@ struct vgic_its {
>>  	u64			cbaser;
>>  	int			creadr;
>>  	int			cwriter;
>> +	struct list_head	device_list;
>> +	struct list_head	collection_list;
>>  };
>>  
>>  struct vgic_dist {
>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>> index b498f06..7f217fa 100644
>> --- a/virt/kvm/arm/its-emul.c
>> +++ b/virt/kvm/arm/its-emul.c
>> @@ -21,6 +21,7 @@
>>  #include <linux/kvm.h>
>>  #include <linux/kvm_host.h>
>>  #include <linux/interrupt.h>
>> +#include <linux/list.h>
>>  
>>  #include <linux/irqchip/arm-gic-v3.h>
>>  #include <kvm/arm_vgic.h>
>> @@ -32,6 +33,25 @@
>>  #include "vgic.h"
>>  #include "its-emul.h"
>>  
>> +struct its_device {
>> +	struct list_head dev_list;
>> +	struct list_head itt;
>> +	u32 device_id;
>> +};
>> +
>> +struct its_collection {
>> +	struct list_head coll_list;
>> +	u32 collection_id;
>> +	u32 target_addr;
>> +};
>> +
>> +struct its_itte {
>> +	struct list_head itte_list;
>> +	struct its_collection *collection;
>> +	u32 lpi;
>> +	u32 event_id;
>> +};
>> +
>>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>>  
>>  /* The distributor lock is held by the VGIC MMIO handler. */
>> @@ -311,6 +331,9 @@ int vits_init(struct kvm *kvm)
>>  
>>  	spin_lock_init(&its->lock);
>>  
>> +	INIT_LIST_HEAD(&its->device_list);
>> +	INIT_LIST_HEAD(&its->collection_list);
>> +
>>  	its->enabled = false;
>>  
>>  	return -ENXIO;
>> @@ -320,11 +343,36 @@ void vits_destroy(struct kvm *kvm)
>>  {
>>  	struct vgic_dist *dist = &kvm->arch.vgic;
>>  	struct vgic_its *its = &dist->its;
>> +	struct its_device *dev;
>> +	struct its_itte *itte;
>> +	struct list_head *dev_cur, *dev_temp;
>> +	struct list_head *cur, *temp;
>>  
>>  	if (!vgic_has_its(kvm))
>>  		return;
>>  
>> +	if (!its->device_list.next)
> Why not using list_empty? But I think I would simply remove this since
> the empty case if handle below...

list_empty() requires the list to be initialized before. This check here
is to detect that map_resources was never called (this is only done on
the first VCPU run) and thus device_list is basically still all zeroes.
If we abort the guest without ever running a VCPU (for instance because
some initialization failed), we call vits_destroy() anyway (because this
is called when tearing down the VGIC device).
So the check is here to detect early that vits_destroy() has been called
without the ITS ever been fully initialized. This fixed a real bug when
the guest start was aborted before the ITS was ever used.
I will add a comment to make this clear.

>> +		return;
>> +
>> +	spin_lock(&its->lock);
>> +	list_for_each_safe(dev_cur, dev_temp, &its->device_list) {
>> +		dev = container_of(dev_cur, struct its_device, dev_list);
> isn't the usage of list_for_each_entry_safe more synthetic here?

If I got this correctly, we need the _safe variant if we want to remove
the list item within the loop. Or am I missing something here?

Cheers,
Andre.


>> +		list_for_each_safe(cur, temp, &dev->itt) {
>> +			itte = (container_of(cur, struct its_itte, itte_list));
> same
> 
> Eric
>> +			list_del(cur);
>> +			kfree(itte);
>> +		}
>> +		list_del(dev_cur);
>> +		kfree(dev);
>> +	}
>> +
>> +	list_for_each_safe(cur, temp, &its->collection_list) {
>> +		list_del(cur);
>> +		kfree(container_of(cur, struct its_collection, coll_list));
>> +	}
>> +
>>  	kfree(dist->pendbaser);
>>  
>>  	its->enabled = false;
>> +	spin_unlock(&its->lock);
>>  }
>>
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 11/15] KVM: arm64: handle pending bit for LPIs in ITS emulation
  2015-08-14 11:58   ` Eric Auger
@ 2015-08-25 14:34     ` Andre Przywara
  2015-08-31  9:45       ` Eric Auger
  0 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-08-25 14:34 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

On 14/08/15 12:58, Eric Auger wrote:
> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>> As the actual LPI number in a guest can be quite high, but is mostly
>> assigned using a very sparse allocation scheme, bitmaps and arrays
>> for storing the virtual interrupt status are a waste of memory.
>> We use our equivalent of the "Interrupt Translation Table Entry"
>> (ITTE) to hold this extra status information for a virtual LPI.
>> As the normal VGIC code cannot use it's fancy bitmaps to manage
>> pending interrupts, we provide a hook in the VGIC code to let the
>> ITS emulation handle the list register queueing itself.
>> LPIs are located in a separate number range (>=8192), so
>> distinguishing them is easy. With LPIs being only edge-triggered, we
>> get away with a less complex IRQ handling.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/arm_vgic.h      |  2 ++
>>  virt/kvm/arm/its-emul.c     | 71 ++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/its-emul.h     |  3 ++
>>  virt/kvm/arm/vgic-v3-emul.c |  2 ++
>>  virt/kvm/arm/vgic.c         | 72 ++++++++++++++++++++++++++++++++++-----------
>>  5 files changed, 133 insertions(+), 17 deletions(-)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 1648668..2a67a10 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -147,6 +147,8 @@ struct vgic_vm_ops {
>>       int     (*init_model)(struct kvm *);
>>       void    (*destroy_model)(struct kvm *);
>>       int     (*map_resources)(struct kvm *, const struct vgic_params *);
>> +     bool    (*queue_lpis)(struct kvm_vcpu *);
>> +     void    (*unqueue_lpi)(struct kvm_vcpu *, int irq);
>>  };
>>
>>  struct vgic_io_device {
>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>> index 7f217fa..b9c40d7 100644
>> --- a/virt/kvm/arm/its-emul.c
>> +++ b/virt/kvm/arm/its-emul.c
>> @@ -50,8 +50,26 @@ struct its_itte {
>>       struct its_collection *collection;
>>       u32 lpi;
>>       u32 event_id;
>> +     bool enabled;
>> +     unsigned long *pending;
>>  };
>>
>> +#define for_each_lpi(dev, itte, kvm) \
>> +     list_for_each_entry(dev, &(kvm)->arch.vgic.its.device_list, dev_list) \
>> +             list_for_each_entry(itte, &(dev)->itt, itte_list)
>> +
> You have a checkpatch error here:
> 
> ERROR: Macros with complex values should be enclosed in parentheses
> #52: FILE: virt/kvm/arm/its-emul.c:57:
> +#define for_each_lpi(dev, itte, kvm) \
> +       list_for_each_entry(dev, &(kvm)->arch.vgic.its.device_list, dev_list) \
> +               list_for_each_entry(itte, &(dev)->itt, itte_list)

I know about that one. The problem is that if I add the parentheses it
breaks the usage below due to the curly brackets. But the definition
above is just so convenient and I couldn't find another neat solution so
far. If you are concerned about that I can give it another try,
otherwise I tend to just ignore checkpatch here.

>> +static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
>> +{
> can't we have the same LPI present in different interrupt translation
> tables? I don't know it is a sensible setting but I did not succeed in
> finding it was not possible.

Thanks to Marc I am happy (and relieved!) to point you to 6.1.1 LPI INTIDs:
"The behavior of the GIC is UNPREDICTABLE if software:
- Maps multiple EventID/DeviceID combinations to the same physical LPI
INTID."

So I exercise the freedom of UNPREDICTABLE here ;-)

>> +     struct its_device *device;
>> +     struct its_itte *itte;
>> +
>> +     for_each_lpi(device, itte, kvm) {
>> +             if (itte->lpi == lpi)
>> +                     return itte;
>> +     }
>> +     return NULL;
>> +}
>> +
>>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>>
>>  /* The distributor lock is held by the VGIC MMIO handler. */
>> @@ -145,6 +163,59 @@ static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
>>       return false;
>>  }
>>
>> +/*
>> + * Find all enabled and pending LPIs and queue them into the list
>> + * registers.
>> + * The dist lock is held by the caller.
>> + */
>> +bool vits_queue_lpis(struct kvm_vcpu *vcpu)
>> +{
>> +     struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
>> +     struct its_device *device;
>> +     struct its_itte *itte;
>> +     bool ret = true;
>> +
>> +     if (!vgic_has_its(vcpu->kvm))
>> +             return true;
>> +     if (!its->enabled || !vcpu->kvm->arch.vgic.lpis_enabled)
>> +             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)
>> +                     continue;
>> +
>> +             __clear_bit(vcpu->vcpu_id, itte->pending);
>> +
>> +             ret &= vgic_queue_irq(vcpu, 0, itte->lpi);
> what if the vgic_queue_irq fails since no LR can be found, the
> itte->pending was cleared so we forget that LPI? shouldn't we restore
> the pending state in ITT? in vgic_queue_hwirq the state change only is
> performed if the vgic_queue_irq succeeds

Of course you are right. I will just only clear the bit if the call
succeeds.

>> +     }
>> +
>> +     spin_unlock(&its->lock);
>> +     return ret;
>> +}
>> +
>> +/* Called with the distributor lock held by the caller. */
>> +void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi)
> I was a bit confused by the name of the function, with regard to
> existing vgic_unqueue_irqs which restores the states in accordance to
> what we have in LR. Wouldn't it make sense to call it
> vits_lpi_set_pending(vcpu, lpi) or something that looks more similar to
> vgic_dist_irq_set_pending setter which I think it mirrors.

Well, vgic_unqueue_irqs() "move[s] pending/active IRQs from LRs to the
distributor", this is what vits_unqueue_lpi() also does, just for one
_single_ LPI instead of iterating over all LRs. Originally I planned to
call vgic_unqueue_irqs on every guest exit, so this would have a more
obvious match.
Admittedly the function does not do much "unqueueing", as this is done
in the caller, so I will think about the renaming part.

>> +{
>> +     struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
>> +     struct its_itte *itte;
>> +
>> +     spin_lock(&its->lock);
>> +
>> +     /* Find the right ITTE and put the pending state back in there */
>> +     itte = find_itte_by_lpi(vcpu->kvm, lpi);
>> +     if (itte)
>> +             __set_bit(vcpu->vcpu_id, itte->pending);
>> +
>> +     spin_unlock(&its->lock);
>> +}
>> +
>>  static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
>>  {
>>       return -ENODEV;
>> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
>> index 472a6d0..cc5d5ff 100644
>> --- a/virt/kvm/arm/its-emul.h
>> +++ b/virt/kvm/arm/its-emul.h
>> @@ -33,4 +33,7 @@ void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>>  int vits_init(struct kvm *kvm);
>>  void vits_destroy(struct kvm *kvm);
>>
>> +bool vits_queue_lpis(struct kvm_vcpu *vcpu);
>> +void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int irq);
>> +
>>  #endif
>> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
>> index 49be3c3..4132c26 100644
>> --- a/virt/kvm/arm/vgic-v3-emul.c
>> +++ b/virt/kvm/arm/vgic-v3-emul.c
>> @@ -948,6 +948,8 @@ void vgic_v3_init_emulation(struct kvm *kvm)
>>       dist->vm_ops.init_model = vgic_v3_init_model;
>>       dist->vm_ops.destroy_model = vgic_v3_destroy_model;
>>       dist->vm_ops.map_resources = vgic_v3_map_resources;
>> +     dist->vm_ops.queue_lpis = vits_queue_lpis;
>> +     dist->vm_ops.unqueue_lpi = vits_unqueue_lpi;
>>
>>       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 49ee92b..9dfd094 100644
>> --- a/virt/kvm/arm/vgic.c
>> +++ b/virt/kvm/arm/vgic.c
>> @@ -95,6 +95,20 @@ static bool queue_sgi(struct kvm_vcpu *vcpu, int irq)
>>       return vcpu->kvm->arch.vgic.vm_ops.queue_sgi(vcpu, irq);
>>  }
>>
>> +static bool vgic_queue_lpis(struct kvm_vcpu *vcpu)
>> +{
>> +     if (vcpu->kvm->arch.vgic.vm_ops.queue_lpis)
>> +             return vcpu->kvm->arch.vgic.vm_ops.queue_lpis(vcpu);
>> +     else
>> +             return true;
>> +}
>> +
>> +static void vgic_unqueue_lpi(struct kvm_vcpu *vcpu, int irq)
>> +{
>> +     if (vcpu->kvm->arch.vgic.vm_ops.unqueue_lpi)
>> +             vcpu->kvm->arch.vgic.vm_ops.unqueue_lpi(vcpu, irq);
>> +}
>> +
>>  int kvm_vgic_map_resources(struct kvm *kvm)
>>  {
>>       return kvm->arch.vgic.vm_ops.map_resources(kvm, vgic);
>> @@ -1135,6 +1149,10 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
>>       for_each_clear_bit(lr, elrsr_ptr, vgic->nr_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)) {
>>                       vlr.state = 0;
>>                       vgic_set_lr(vcpu, lr, vlr);
>> @@ -1147,25 +1165,33 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
>>  static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>>                                int lr_nr, int sgi_source_id)
>>  {
>> +     struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>       struct vgic_lr vlr;
>>
>>       vlr.state = 0;
>>       vlr.irq = irq;
>>       vlr.source = sgi_source_id;
>>
>> -     if (vgic_irq_is_active(vcpu, irq)) {
>> -             vlr.state |= LR_STATE_ACTIVE;
>> -             kvm_debug("Set active, clear distributor: 0x%x\n", vlr.state);
>> -             vgic_irq_clear_active(vcpu, irq);
>> -             vgic_update_state(vcpu->kvm);
>> -     } else if (vgic_dist_irq_is_pending(vcpu, irq)) {
>> -             vlr.state |= LR_STATE_PENDING;
>> -             kvm_debug("Set pending: 0x%x\n", vlr.state);
>> -     }
>> -
>> -     if (!vgic_irq_is_edge(vcpu, irq))
>> -             vlr.state |= LR_EOI_INT;
>> +     /* We care only about state for SGIs/PPIs/SPIs, not for LPIs */
>> +     if (irq < dist->nr_irqs) {
>> +             if (vgic_irq_is_active(vcpu, irq)) {
>> +                     vlr.state |= LR_STATE_ACTIVE;
>> +                     kvm_debug("Set active, clear distributor: 0x%x\n",
>> +                               vlr.state);
>> +                     vgic_irq_clear_active(vcpu, irq);
>> +                     vgic_update_state(vcpu->kvm);
>> +             } else if (vgic_dist_irq_is_pending(vcpu, irq)) {
>> +                     vlr.state |= LR_STATE_PENDING;
>> +                     kvm_debug("Set pending: 0x%x\n", vlr.state);
>> +             }
>>
>> +             if (!vgic_irq_is_edge(vcpu, irq))
>> +                     vlr.state |= LR_EOI_INT;
>> +     } else {
>> +             /* If this is an LPI, it can only be pending */
>> +             if (irq >= 8192)
>> +                     vlr.state |= LR_STATE_PENDING;
>> +     }
>>       vgic_set_lr(vcpu, lr_nr, vlr);
>>       vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
>>  }
>> @@ -1177,7 +1203,6 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>>   */
>>  bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>>  {
>> -     struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>       u64 elrsr = vgic_get_elrsr(vcpu);
>>       unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
>>       int lr;
>> @@ -1185,7 +1210,6 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>>       /* Sanitize the input... */
>>       BUG_ON(sgi_source_id & ~7);
>>       BUG_ON(sgi_source_id && irq >= VGIC_NR_SGIS);
>> -     BUG_ON(irq >= dist->nr_irqs);
> Is it safe to remove that check. What if it is attempted to inject an
> SPI larger than supported. I think you should refine the check but not
> remove it.

The check is now in vgic_queue_irq_to_lr (see above), where we
differentiate between LPIs (>=8192) and SPIs (<dist->nr_irqs). Please
correct me if I am wrong on this, but since we are not setting any state
bits the vgic_set_lr() and vgic_sync_lr_elrsr() calls should be NOPs in
this case, right?
I may re-add the explicit check here for the sake of clarity, though.

>>
>>       kvm_debug("Queue IRQ%d\n", irq);
>>
>> @@ -1265,8 +1289,12 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>>                       overflow = 1;
>>       }
>>
>> -
>> -
>> +     /*
>> +      * LPIs are not mapped in our bitmaps, so we leave the iteration
>> +      * to the ITS emulation code.
>> +      */
>> +     if (!vgic_queue_lpis(vcpu))
>> +             overflow = 1;
>>
>>  epilog:
>>       if (overflow) {
>> @@ -1387,6 +1415,16 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>>       for_each_clear_bit(lr_nr, elrsr_ptr, vgic_cpu->nr_lr) {
>>               vlr = vgic_get_lr(vcpu, lr_nr);
>>
>> +             /* LPIs are handled separately */
>> +             if (vlr.irq >= 8192) {
>> +                     /* We just need to take care about still pending LPIs */
>> +                     if (vlr.state & LR_STATE_PENDING) {
>> +                             vgic_unqueue_lpi(vcpu, vlr.irq);
>> +                             pending = true;
>> +                     }
>> +                     continue;
> don't we need to reset the LR & update elrsr?

Mmmh, interesting, I just wonder how it worked before. I will move most
of the lower part into an else clause and call the LR maintainance code
in both cases.

Cheers,
Andre.

>> +             }
>> +
>>               BUG_ON(!(vlr.state & LR_STATE_MASK));
>>               pending = true;
>>
>> @@ -1411,7 +1449,7 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>>       }
>>       vgic_update_state(vcpu->kvm);
>>
>> -     /* vgic_update_state would not cover only-active IRQs */
>> +     /* vgic_update_state would not cover only-active IRQs or LPIs */
>>       if (pending)
>>               set_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu);
>>  }
>>
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 12/15] KVM: arm64: sync LPI configuration and pending tables
  2015-08-14 11:58   ` Eric Auger
  2015-08-14 12:35     ` Eric Auger
@ 2015-08-25 15:27     ` Andre Przywara
  2015-08-31  9:47       ` Eric Auger
  1 sibling, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-08-25 15:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

On 14/08/15 12:58, Eric Auger wrote:
> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>> The LPI configuration and pending tables of the GICv3 LPIs are held
>> in tables in (guest) memory. To achieve reasonable performance, we
>> cache this data in our own data structures, so we need to sync those
>> two views from time to time. This behaviour is well described in the
>> GICv3 spec and is also exercised by hardware, so the sync points are
>> well known.
>>
>> Provide functions that read the guest memory and store the
>> information from the configuration and pending tables in the kernel.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
> would help to have change log between v1 -> v2 (valid for the whole series)
>>  include/kvm/arm_vgic.h  |   2 +
>>  virt/kvm/arm/its-emul.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/its-emul.h |   3 ++
>>  3 files changed, 129 insertions(+)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 2a67a10..323c33a 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -167,6 +167,8 @@ struct vgic_its {
>>  	int			cwriter;
>>  	struct list_head	device_list;
>>  	struct list_head	collection_list;
>> +	/* memory used for buffering guest's memory */
>> +	void			*buffer_page;
>>  };
>>  
>>  struct vgic_dist {
>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>> index b9c40d7..05245cb 100644
>> --- a/virt/kvm/arm/its-emul.c
>> +++ b/virt/kvm/arm/its-emul.c
>> @@ -50,6 +50,7 @@ struct its_itte {
>>  	struct its_collection *collection;
>>  	u32 lpi;
>>  	u32 event_id;
>> +	u8 priority;
>>  	bool enabled;
>>  	unsigned long *pending;
>>  };
>> @@ -70,8 +71,124 @@ static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
>>  	return NULL;
>>  }
>>  
>> +#define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
>> +#define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
>> +
>> +/* stores the priority and enable bit for a given LPI */
>> +static void update_lpi_config(struct kvm *kvm, struct its_itte *itte, u8 prop)
>> +{
>> +	itte->priority = LPI_PROP_PRIORITY(prop);
>> +	itte->enabled  = LPI_PROP_ENABLE_BIT(prop);
>> +}
>> +
>> +#define GIC_LPI_OFFSET 8192
>> +
>> +/* We scan the table in chunks the size of the smallest page size */
> 4kB chunks?

Marc was complaining about this wording, I think. The rationale was that
"4K" is already in the code and thus does not need to be repeated in the
comment, whereas the comment should explain the meaning of the value.

>> +#define CHUNK_SIZE 4096U
>> +
>>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>>  
>> +static int nr_idbits_propbase(u64 propbaser)
>> +{
>> +	int nr_idbits = (1U << (propbaser & 0x1f)) + 1;
>> +
>> +	return max(nr_idbits, INTERRUPT_ID_BITS_ITS);
>> +}
>> +
>> +/*
>> + * Scan the whole LPI configuration table and put the LPI configuration
>> + * data in our own data structures. This relies on the LPI being
>> + * mapped before.
>> + */
>> +static bool its_update_lpis_configuration(struct kvm *kvm)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +	u8 *prop = dist->its.buffer_page;
>> +	u32 tsize;
>> +	gpa_t propbase;
>> +	int lpi = GIC_LPI_OFFSET;
>> +	struct its_itte *itte;
>> +	struct its_device *device;
>> +	int ret;
>> +
>> +	propbase = BASER_BASE_ADDRESS(dist->propbaser);
>> +	tsize = nr_idbits_propbase(dist->propbaser);
>> +
>> +	while (tsize > 0) {
>> +		int chunksize = min(tsize, CHUNK_SIZE);
>> +
>> +		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
> I think you still have the spin_lock issue  since if my understanding is
> correct this is called from
> vgic_handle_mmio_access/vcall_range_handler/gic_enable_lpis
> where vgic_handle_mmio_access. Or does it take another path?

Well, it's (also) called on handling the INVALL command, but you are
right that on that enable path the dist lock is held. I reckon that this
init part isn't racy so that shouldn't be a problem (famous last words ;-).
Let me see whether I can find a way to just drop the lock around the
while loop.

Cheers,
Andre.

> 
> Shouldn't we create a new kvm_io_device to avoid holding the dist lock?
> 
> Eric

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 12/15] KVM: arm64: sync LPI configuration and pending tables
  2015-08-14 12:35     ` Eric Auger
@ 2015-08-25 15:47       ` Andre Przywara
  2015-08-31  9:51         ` Eric Auger
  0 siblings, 1 reply; 69+ messages in thread
From: Andre Przywara @ 2015-08-25 15:47 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

On 14/08/15 13:35, Eric Auger wrote:
> On 08/14/2015 01:58 PM, Eric Auger wrote:
>> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>>> The LPI configuration and pending tables of the GICv3 LPIs are held
>>> in tables in (guest) memory. To achieve reasonable performance, we
>>> cache this data in our own data structures, so we need to sync those
>>> two views from time to time. This behaviour is well described in the
>>> GICv3 spec and is also exercised by hardware, so the sync points are
>>> well known.
>>>
>>> Provide functions that read the guest memory and store the
>>> information from the configuration and pending tables in the kernel.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>> would help to have change log between v1 -> v2 (valid for the whole series)
>>>  include/kvm/arm_vgic.h  |   2 +
>>>  virt/kvm/arm/its-emul.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/its-emul.h |   3 ++
>>>  3 files changed, 129 insertions(+)
>>>
>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>> index 2a67a10..323c33a 100644
>>> --- a/include/kvm/arm_vgic.h
>>> +++ b/include/kvm/arm_vgic.h
>>> @@ -167,6 +167,8 @@ struct vgic_its {
>>>  	int			cwriter;
>>>  	struct list_head	device_list;
>>>  	struct list_head	collection_list;
>>> +	/* memory used for buffering guest's memory */
>>> +	void			*buffer_page;
>>>  };
>>>  
>>>  struct vgic_dist {
>>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>>> index b9c40d7..05245cb 100644
>>> --- a/virt/kvm/arm/its-emul.c
>>> +++ b/virt/kvm/arm/its-emul.c
>>> @@ -50,6 +50,7 @@ struct its_itte {
>>>  	struct its_collection *collection;
>>>  	u32 lpi;
>>>  	u32 event_id;
>>> +	u8 priority;
>>>  	bool enabled;
>>>  	unsigned long *pending;
>>>  };
>>> @@ -70,8 +71,124 @@ static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
>>>  	return NULL;
>>>  }
>>>  
>>> +#define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
>>> +#define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
>>> +
>>> +/* stores the priority and enable bit for a given LPI */
>>> +static void update_lpi_config(struct kvm *kvm, struct its_itte *itte, u8 prop)
>>> +{
>>> +	itte->priority = LPI_PROP_PRIORITY(prop);
>>> +	itte->enabled  = LPI_PROP_ENABLE_BIT(prop);
>>> +}
>>> +
>>> +#define GIC_LPI_OFFSET 8192
>>> +
>>> +/* We scan the table in chunks the size of the smallest page size */
>> 4kB chunks?
>>> +#define CHUNK_SIZE 4096U
>>> +
>>>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>>>  
>>> +static int nr_idbits_propbase(u64 propbaser)
>>> +{
>>> +	int nr_idbits = (1U << (propbaser & 0x1f)) + 1;
>>> +
>>> +	return max(nr_idbits, INTERRUPT_ID_BITS_ITS);
>>> +}
>>> +
>>> +/*
>>> + * Scan the whole LPI configuration table and put the LPI configuration
>>> + * data in our own data structures. This relies on the LPI being
>>> + * mapped before.
>>> + */
>>> +static bool its_update_lpis_configuration(struct kvm *kvm)
>>> +{
>>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>>> +	u8 *prop = dist->its.buffer_page;
>>> +	u32 tsize;
>>> +	gpa_t propbase;
>>> +	int lpi = GIC_LPI_OFFSET;
>>> +	struct its_itte *itte;
>>> +	struct its_device *device;
>>> +	int ret;
>>> +
>>> +	propbase = BASER_BASE_ADDRESS(dist->propbaser);
>>> +	tsize = nr_idbits_propbase(dist->propbaser);
>>> +
>>> +	while (tsize > 0) {
>>> +		int chunksize = min(tsize, CHUNK_SIZE);
>>> +
>>> +		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
>> I think you still have the spin_lock issue  since if my understanding is
>> correct this is called from
>> vgic_handle_mmio_access/vcall_range_handler/gic_enable_lpis
>> where vgic_handle_mmio_access. Or does it take another path?
>>
>> Shouldn't we create a new kvm_io_device to avoid holding the dist lock?
> 
> Sorry I forgot it was the case already. But currently we always register
> the same io ops (registration entry point being
> vgic_register_kvm_io_dev) and maybe we should have separate dispatcher
> function for dist, redit and its?

What would be the idea behind it? To have separate locks for each? I
don't think that will work, as some ITS functions are called from GICv3
register handler functions which manipulate members of the distributor
structure. So I am more in favour of dropping the dist lock in these
cases before handing off execution to ITS specific functions.

Cheers,
Andre.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 10/15] KVM: arm64: add data structures to model ITS interrupt translation
  2015-08-25 11:15     ` Andre Przywara
@ 2015-08-27 14:16       ` Eric Auger
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Auger @ 2015-08-27 14:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andre,
On 08/25/2015 01:15 PM, Andre Przywara wrote:
> Hi Eric,
> 
> On 13/08/15 16:46, Eric Auger wrote:
>>
>> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>>> The GICv3 Interrupt Translation Service (ITS) uses tables in memory
>>> to allow a sophisticated interrupt routing. It features device tables,
>>> an interrupt table per device and a table connecting "collections" to
>>> actual CPUs (aka. redistributors in the GICv3 lingo).
>>> Since the interrupt numbers for the LPIs are allocated quite sparsely
>>> and the range can be quite huge (8192 LPIs being the minimum), using
>>> bitmaps or arrays for storing information is a waste of memory.
>>> We use linked lists instead, which we iterate linearily. This works
>>> very well with the actual number of LPIs/MSIs in the guest being
>>> quite low. Should the number of LPIs exceed the number where iterating
>>> through lists seems acceptable, we can later revisit this and use more
>>> efficient data structures.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  include/kvm/arm_vgic.h  |  3 +++
>>>  virt/kvm/arm/its-emul.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>  2 files changed, 51 insertions(+)
>>>
>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>> index b432055..1648668 100644
>>> --- a/include/kvm/arm_vgic.h
>>> +++ b/include/kvm/arm_vgic.h
>>> @@ -25,6 +25,7 @@
>>>  #include <linux/spinlock.h>
>>>  #include <linux/types.h>
>>>  #include <kvm/iodev.h>
>>> +#include <linux/list.h>
>>>  
>>>  #define VGIC_NR_IRQS_LEGACY	256
>>>  #define VGIC_NR_SGIS		16
>>> @@ -162,6 +163,8 @@ struct vgic_its {
>>>  	u64			cbaser;
>>>  	int			creadr;
>>>  	int			cwriter;
>>> +	struct list_head	device_list;
>>> +	struct list_head	collection_list;
>>>  };
>>>  
>>>  struct vgic_dist {
>>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>>> index b498f06..7f217fa 100644
>>> --- a/virt/kvm/arm/its-emul.c
>>> +++ b/virt/kvm/arm/its-emul.c
>>> @@ -21,6 +21,7 @@
>>>  #include <linux/kvm.h>
>>>  #include <linux/kvm_host.h>
>>>  #include <linux/interrupt.h>
>>> +#include <linux/list.h>
>>>  
>>>  #include <linux/irqchip/arm-gic-v3.h>
>>>  #include <kvm/arm_vgic.h>
>>> @@ -32,6 +33,25 @@
>>>  #include "vgic.h"
>>>  #include "its-emul.h"
>>>  
>>> +struct its_device {
>>> +	struct list_head dev_list;
>>> +	struct list_head itt;
>>> +	u32 device_id;
>>> +};
>>> +
>>> +struct its_collection {
>>> +	struct list_head coll_list;
>>> +	u32 collection_id;
>>> +	u32 target_addr;
>>> +};
>>> +
>>> +struct its_itte {
>>> +	struct list_head itte_list;
>>> +	struct its_collection *collection;
>>> +	u32 lpi;
>>> +	u32 event_id;
>>> +};
>>> +
>>>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>>>  
>>>  /* The distributor lock is held by the VGIC MMIO handler. */
>>> @@ -311,6 +331,9 @@ int vits_init(struct kvm *kvm)
>>>  
>>>  	spin_lock_init(&its->lock);
>>>  
>>> +	INIT_LIST_HEAD(&its->device_list);
>>> +	INIT_LIST_HEAD(&its->collection_list);
>>> +
>>>  	its->enabled = false;
>>>  
>>>  	return -ENXIO;
>>> @@ -320,11 +343,36 @@ void vits_destroy(struct kvm *kvm)
>>>  {
>>>  	struct vgic_dist *dist = &kvm->arch.vgic;
>>>  	struct vgic_its *its = &dist->its;
>>> +	struct its_device *dev;
>>> +	struct its_itte *itte;
>>> +	struct list_head *dev_cur, *dev_temp;
>>> +	struct list_head *cur, *temp;
>>>  
>>>  	if (!vgic_has_its(kvm))
>>>  		return;
>>>  
>>> +	if (!its->device_list.next)
>> Why not using list_empty? But I think I would simply remove this since
>> the empty case if handle below...
> 
> list_empty() requires the list to be initialized before. This check here
> is to detect that map_resources was never called (this is only done on
> the first VCPU run) and thus device_list is basically still all zeroes.
> If we abort the guest without ever running a VCPU (for instance because
> some initialization failed), we call vits_destroy() anyway (because this
> is called when tearing down the VGIC device).
> So the check is here to detect early that vits_destroy() has been called
> without the ITS ever been fully initialized. This fixed a real bug when
> the guest start was aborted before the ITS was ever used.
> I will add a comment to make this clear.

OK. My next question is why don't we call vits_init in vgic_init after
dist->nr_cpus? I had in mind map_resources was linked to the setting of
vgic_dist_base & vgic_cpu_base. Here you do not depend on those
addresses? Do I miss smthg?
> 
>>> +		return;
>>> +
>>> +	spin_lock(&its->lock);
>>> +	list_for_each_safe(dev_cur, dev_temp, &its->device_list) {
>>> +		dev = container_of(dev_cur, struct its_device, dev_list);
>> isn't the usage of list_for_each_entry_safe more synthetic here?
Sorry my point was about the _ENTRY_ variant that should avoid to use
container_of, isn't it?

Eric
> 
> If I got this correctly, we need the _safe variant if we want to remove
> the list item within the loop. Or am I missing something here?
> 
> Cheers,
> Andre.
> 
> 
>>> +		list_for_each_safe(cur, temp, &dev->itt) {
>>> +			itte = (container_of(cur, struct its_itte, itte_list));
>> same
>>
>> Eric
>>> +			list_del(cur);
>>> +			kfree(itte);
>>> +		}
>>> +		list_del(dev_cur);
>>> +		kfree(dev);
>>> +	}
>>> +
>>> +	list_for_each_safe(cur, temp, &its->collection_list) {
>>> +		list_del(cur);
>>> +		kfree(container_of(cur, struct its_collection, coll_list));
>>> +	}
>>> +
>>>  	kfree(dist->pendbaser);
>>>  
>>>  	its->enabled = false;
>>> +	spin_unlock(&its->lock);
>>>  }
>>>
>>

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-08-24 16:33     ` Andre Przywara
@ 2015-08-31  8:42       ` Eric Auger
  2015-09-02  9:00         ` Andre Przywara
  0 siblings, 1 reply; 69+ messages in thread
From: Eric Auger @ 2015-08-31  8:42 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/24/2015 06:33 PM, Andre Przywara wrote:
> Hi Eric,
> 
> On 12/08/15 10:01, Eric Auger wrote:
> ....
>>> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
>>> index bc40137..394622c 100644
>>> --- a/virt/kvm/arm/vgic.c
>>> +++ b/virt/kvm/arm/vgic.c
>>> @@ -79,7 +79,6 @@
>>>  #include "vgic.h"
>>>  
>>>  static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu);
>>> -static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu);
>>>  static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr);
>>>  static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr, struct vgic_lr lr_desc);
>>>  
>>> @@ -647,6 +646,17 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
>>>  	return false;
>>>  }
>>>  
>>> +static void vgic_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
>>> +			       struct vgic_lr vlr)
>>> +{
>>> +	vgic_ops->sync_lr_elrsr(vcpu, lr, vlr);
>>> +}
>> why not renaming this into vgic_set_elrsr. This would be homogeneous
>> with other virtual interface control register setters?
> 
> But that would involve renaming the vgic_ops members as well to be
> consistent, right?
yes
 As there is no change in the behaviour, a naming
> change sounds unmotivated to me. And _set_ wouldn't be exact, as this
> function deals only with only one bit at a time and allows to clear it
> as well.
OK. Not that much important. That's just I had in mind the
__kvm_vgic_SYNC_hwstate which has more intelligence ;-) That function
just sets one bit of elrsr ...
> 
>>> +
>>> +static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
>>> +{
>>> +	return vgic_ops->get_elrsr(vcpu);
>>> +}
>> If I am not wrong, each time you manipulate the elrsr you handle the
>> bitmap. why not directly returning an unsigned long * then (elrsr_ptr)?
> 
> Because the pointer needs to point somewhere, and that storage is
> currently located on the caller's stack. Directly returning a pointer
> would require the caller to provide some memory for the u64, which does
> not save you so much in terms on LOC:
> 
> -	u64 elrsr = vgic_get_elrsr(vcpu);
> -	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
> +	u64 elrsr;
> +	unsigned long *elrsr_ptr = vgic_get_elrsr_bm(vcpu, &elrsr);
> 
> Also we need u64_to_bitmask() in one case when converting the EISR
> value, so we cannot get lost of that function.

OK fair enough
> 
>>> +
>>>  /**
>>>   * vgic_unqueue_irqs - move pending/active IRQs from LRs to the distributor
>>>   * @vgic_cpu: Pointer to the vgic_cpu struct holding the LRs
>>> @@ -658,9 +668,11 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
>>>  void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
>>>  {
>>>  	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>> +	u64 elrsr = vgic_get_elrsr(vcpu);
>>> +	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
>>>  	int i;
>>>  
>>> -	for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) {
>>> +	for_each_clear_bit(i, elrsr_ptr, vgic_cpu->nr_lr) {
>>>  		struct vgic_lr lr = vgic_get_lr(vcpu, i);
>>>  
>>>  		/*
>>> @@ -703,7 +715,7 @@ void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
>>>  		 * Mark the LR as free for other use.
>>>  		 */
>>>  		BUG_ON(lr.state & LR_STATE_MASK);
>>> -		vgic_retire_lr(i, lr.irq, vcpu);
>>> +		vgic_sync_lr_elrsr(vcpu, i, lr);
>>>  		vgic_irq_clear_queued(vcpu, lr.irq);
>>>  
>>>  		/* Finally update the VGIC state. */
>>> @@ -1011,17 +1023,6 @@ static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr,
>>>  	vgic_ops->set_lr(vcpu, lr, vlr);
>>>  }
>>>  
>>> -static void vgic_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
>>> -			       struct vgic_lr vlr)
>>> -{
>>> -	vgic_ops->sync_lr_elrsr(vcpu, lr, vlr);
>>> -}
>>> -
>>> -static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
>>> -{
>>> -	return vgic_ops->get_elrsr(vcpu);
>>> -}
>>> -
>>>  static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
>>>  {
>>>  	return vgic_ops->get_eisr(vcpu);
>>> @@ -1062,18 +1063,6 @@ static inline void vgic_enable(struct kvm_vcpu *vcpu)
>>>  	vgic_ops->enable(vcpu);
>>>  }
>>>  
>>> -static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
>>> -{
>>> -	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>> -	struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr);
>>> -
>>> -	vlr.state = 0;
>>> -	vgic_set_lr(vcpu, lr_nr, vlr);
>>> -	clear_bit(lr_nr, vgic_cpu->lr_used);
>>> -	vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
>>> -	vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
>>> -}
>>> -
>>>  /*
>>>   * An interrupt may have been disabled after being made pending on the
>>>   * CPU interface (the classic case is a timer running while we're
>>> @@ -1085,23 +1074,32 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
>>>   */
>>>  static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
>>>  {
>>> -	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>> +	u64 elrsr = vgic_get_elrsr(vcpu);
>>> +	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
>> if you agree with above modif I would simply rename elrsr_ptr into elrsr.
>>>  	int lr;
>>> +	struct vgic_lr vlr;
>> why moving this declaration here. I think this can remain in the block.
> 
> Possibly. Don't remember the reason of this move, I think it was due to
> some other changes I later removed. I will revert it.
> 
>>>  
>>> -	for_each_set_bit(lr, vgic_cpu->lr_used, vgic->nr_lr) {
>>> -		struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
>>> +	for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) {
>>> +		vlr = vgic_get_lr(vcpu, lr);
>>>  
>>>  		if (!vgic_irq_is_enabled(vcpu, vlr.irq)) {
>>> -			vgic_retire_lr(lr, vlr.irq, vcpu);
>>> -			if (vgic_irq_is_queued(vcpu, vlr.irq))
>>> -				vgic_irq_clear_queued(vcpu, vlr.irq);
>>> +			vlr.state = 0;
>>> +			vgic_set_lr(vcpu, lr, vlr);
>>> +			vgic_sync_lr_elrsr(vcpu, lr, vlr);
>> vgic_set_elrsr?
>>
>> the "if (vgic_irq_is_queued(vcpu, vlr.irq))" check disappeared. This
>> change might be introduced separately.
> 
> OK, this is an admittedly independent optimization to avoid the needless
> check for "clear only set bits". I didn't find it useful to spin a
> separate patch for this, so just fixed this while reworking this code
> anyway.
OK
> 
>>> +			vgic_irq_clear_queued(vcpu, vlr.irq);
>>>  		}
>>>  	}
>>>  }
>>>  
>>>  static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>>> -				 int lr_nr, struct vgic_lr vlr)
>> I don't think this change of proto is compatible with Marc's "KVM:
>> arm/arm64: vgic: Allow HW interrupts to be queued to a guest".
>> I think we need to keep former signature.
> 
> I will need to rebase my series on top of the 4.3 pull request anyway,
> so: yes, I will adapt to Marc's series.
> 
>>> +				 int lr_nr, int sgi_source_id)
>>>  {
>>> +	struct vgic_lr vlr;
>>> +
>>> +	vlr.state = 0;
>>> +	vlr.irq = irq;
>>> +	vlr.source = sgi_source_id;
>>> +
>>>  	if (vgic_irq_is_active(vcpu, irq)) {
>>>  		vlr.state |= LR_STATE_ACTIVE;
>>>  		kvm_debug("Set active, clear distributor: 0x%x\n", vlr.state);
>>> @@ -1126,9 +1124,9 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>>>   */
>>>  bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>>>  {
>>> -	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>>  	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>> -	struct vgic_lr vlr;
>>> +	u64 elrsr = vgic_get_elrsr(vcpu);
>>> +	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
>>>  	int lr;
>>>  
>>>  	/* Sanitize the input... */
>>> @@ -1138,42 +1136,20 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>>>  
>>>  	kvm_debug("Queue IRQ%d\n", irq);
>>>  
>>> -	lr = vgic_cpu->vgic_irq_lr_map[irq];
>>> -
>>> -	/* Do we have an active interrupt for the same CPUID? */
>>> -	if (lr != LR_EMPTY) {
>>> -		vlr = vgic_get_lr(vcpu, lr);
>>> -		if (vlr.source == sgi_source_id) {
>>> -			kvm_debug("LR%d piggyback for IRQ%d\n", lr, vlr.irq);
>>> -			BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
>>> -			vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
>>> -			return true;
>>> -		}
>>> -	}
>>> +	lr = find_first_bit(elrsr_ptr, vgic->nr_lr);
>>>  
>>> -	/* Try to use another LR for this interrupt */
>>> -	lr = find_first_zero_bit((unsigned long *)vgic_cpu->lr_used,
>>> -			       vgic->nr_lr);
>>>  	if (lr >= vgic->nr_lr)
>>>  		return false;
>>>  
>>>  	kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id);
>>> -	vgic_cpu->vgic_irq_lr_map[irq] = lr;
>>> -	set_bit(lr, vgic_cpu->lr_used);
>>>  
>>> -	vlr.irq = irq;
>>> -	vlr.source = sgi_source_id;
>>> -	vlr.state = 0;
>>> -	vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
>>> +	vgic_queue_irq_to_lr(vcpu, irq, lr, sgi_source_id);
>>>  
>>>  	return true;
>>>  }
>>>  
>>>  static bool vgic_queue_hwirq(struct kvm_vcpu *vcpu, int irq)
>>>  {
>>> -	if (!vgic_can_sample_irq(vcpu, irq))
>>> -		return true; /* level interrupt, already queued */
>>> -
>> I think that change needs to be introduced in a separate patch as the
>> other one mentioned above and justified since it affects the state machine.
> 
> But this change is dependent on this patch: it will not work without
> this patch and this patch will not work without that change.
> So the idea is that on returning from the guest we now harvest all
> _used_ LRs by copying their state back into the distributor. The
> previous behaviour was to just check _unused_ LRs for completed IRQs.
> So now all IRQs need to be re-inserted into the LRs before the next
> guest run, that's why we have to remove the test which skipped this for
> IRQs where the code knew that they were still in the LRs.
> Does that make sense?
In level sensitive case, what if the IRQ'LR state was active. LR was
kept intact. IRQ is queued. With previous code we wouldn't inject a new
IRQ. Here aren't we going to inject it?

In the sync when you move the IRQ from the LR reg to the state variable,
shouldn't you reset the queued state for level sensitive case? In such a
case I think you could keep that check.

Cheers

Eric
> 
> Cheers,
> Andre.
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 05/15] KVM: arm/arm64: make GIC frame address initialization model specific
  2015-08-24 17:24     ` Andre Przywara
@ 2015-08-31  9:31       ` Eric Auger
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Auger @ 2015-08-31  9:31 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/24/2015 07:24 PM, Andre Przywara wrote:
> Hi,
> 
> On 12/08/15 14:02, Eric Auger wrote:
>> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>>> Currently we initialize all the possible GIC frame addresses in one
>>> function, without looking at the specific GIC model we instantiate
>>> for the guest.
>>> As this gets confusing when adding another VGIC model later, lets
>>> move these initializations into the respective model's init 
>> nit: tobe more precise the init emulation function (not the
>> vgic_v2/v3_init_model model's init function). pfouh?! ;-)
>> functions.
> 
> OK, will try to find a wording that is not completely confusing.
> 
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  virt/kvm/arm/vgic-v2-emul.c | 3 +++
>>>  virt/kvm/arm/vgic-v3-emul.c | 3 +++
>>>  virt/kvm/arm/vgic.c         | 3 ---
>>>  3 files changed, 6 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c
>>> index 1390797..8faa28c 100644
>>> --- a/virt/kvm/arm/vgic-v2-emul.c
>>> +++ b/virt/kvm/arm/vgic-v2-emul.c
>>> @@ -567,6 +567,9 @@ void vgic_v2_init_emulation(struct kvm *kvm)
>>>  	dist->vm_ops.init_model = vgic_v2_init_model;
>>>  	dist->vm_ops.map_resources = vgic_v2_map_resources;
>>>  
>>> +	dist->vgic_cpu_base = VGIC_ADDR_UNDEF;
>>> +	dist->vgic_dist_base = VGIC_ADDR_UNDEF;
>> Looks strange to see the common dist_base here. Why don't you leave it
>> in common part, kvm_vgic_create; all the more so you left
>> kvm->arch.vgic.vctrl_base = vgic->vctrl_base in kvm_vgic_create.
> 
> The idea behind this is that dist_base refers to similar, but not
> identical distributors (v2 vs. v3), so I found it a good idea to
> initialize it in here. Also vctrl_base is host facing and not set by
> userland, so this doesn't really compare here.
ok

Eric
> 
> Cheers,
> Andre.
> 
>>> +
>>>  	kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
>>>  }
>>>  
>>> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
>>> index d2eeb20..1f42348 100644
>>> --- a/virt/kvm/arm/vgic-v3-emul.c
>>> +++ b/virt/kvm/arm/vgic-v3-emul.c
>>> @@ -885,6 +885,9 @@ void vgic_v3_init_emulation(struct kvm *kvm)
>>>  	dist->vm_ops.destroy_model = vgic_v3_destroy_model;
>>>  	dist->vm_ops.map_resources = vgic_v3_map_resources;
>>>  
>>> +	dist->vgic_dist_base = VGIC_ADDR_UNDEF;
>>> +	dist->vgic_redist_base = VGIC_ADDR_UNDEF;
>>> +
>>>  	kvm->arch.max_vcpus = KVM_MAX_VCPUS;
>>>  }
>>>  
>>> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
>>> index cc8f5ed..59f1801 100644
>>> --- a/virt/kvm/arm/vgic.c
>>> +++ b/virt/kvm/arm/vgic.c
>>> @@ -1830,9 +1830,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
>>>  	kvm->arch.vgic.in_kernel = true;
>>>  	kvm->arch.vgic.vgic_model = type;
>>>  	kvm->arch.vgic.vctrl_base = vgic->vctrl_base;
>>> -	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
>>> -	kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
>>> -	kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
>>>  
>>>  out_unlock:
>>>  	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
>>>
>>

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 11/15] KVM: arm64: handle pending bit for LPIs in ITS emulation
  2015-08-25 14:34     ` Andre Przywara
@ 2015-08-31  9:45       ` Eric Auger
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Auger @ 2015-08-31  9:45 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/25/2015 04:34 PM, Andre Przywara wrote:
> Hi Eric,
> 
> On 14/08/15 12:58, Eric Auger wrote:
>> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>>> As the actual LPI number in a guest can be quite high, but is mostly
>>> assigned using a very sparse allocation scheme, bitmaps and arrays
>>> for storing the virtual interrupt status are a waste of memory.
>>> We use our equivalent of the "Interrupt Translation Table Entry"
>>> (ITTE) to hold this extra status information for a virtual LPI.
>>> As the normal VGIC code cannot use it's fancy bitmaps to manage
>>> pending interrupts, we provide a hook in the VGIC code to let the
>>> ITS emulation handle the list register queueing itself.
>>> LPIs are located in a separate number range (>=8192), so
>>> distinguishing them is easy. With LPIs being only edge-triggered, we
>>> get away with a less complex IRQ handling.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  include/kvm/arm_vgic.h      |  2 ++
>>>  virt/kvm/arm/its-emul.c     | 71 ++++++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/its-emul.h     |  3 ++
>>>  virt/kvm/arm/vgic-v3-emul.c |  2 ++
>>>  virt/kvm/arm/vgic.c         | 72 ++++++++++++++++++++++++++++++++++-----------
>>>  5 files changed, 133 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>> index 1648668..2a67a10 100644
>>> --- a/include/kvm/arm_vgic.h
>>> +++ b/include/kvm/arm_vgic.h
>>> @@ -147,6 +147,8 @@ struct vgic_vm_ops {
>>>       int     (*init_model)(struct kvm *);
>>>       void    (*destroy_model)(struct kvm *);
>>>       int     (*map_resources)(struct kvm *, const struct vgic_params *);
>>> +     bool    (*queue_lpis)(struct kvm_vcpu *);
>>> +     void    (*unqueue_lpi)(struct kvm_vcpu *, int irq);
>>>  };
>>>
>>>  struct vgic_io_device {
>>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>>> index 7f217fa..b9c40d7 100644
>>> --- a/virt/kvm/arm/its-emul.c
>>> +++ b/virt/kvm/arm/its-emul.c
>>> @@ -50,8 +50,26 @@ struct its_itte {
>>>       struct its_collection *collection;
>>>       u32 lpi;
>>>       u32 event_id;
>>> +     bool enabled;
>>> +     unsigned long *pending;
>>>  };
>>>
>>> +#define for_each_lpi(dev, itte, kvm) \
>>> +     list_for_each_entry(dev, &(kvm)->arch.vgic.its.device_list, dev_list) \
>>> +             list_for_each_entry(itte, &(dev)->itt, itte_list)
>>> +
>> You have a checkpatch error here:
>>
>> ERROR: Macros with complex values should be enclosed in parentheses
>> #52: FILE: virt/kvm/arm/its-emul.c:57:
>> +#define for_each_lpi(dev, itte, kvm) \
>> +       list_for_each_entry(dev, &(kvm)->arch.vgic.its.device_list, dev_list) \
>> +               list_for_each_entry(itte, &(dev)->itt, itte_list)
> 
> I know about that one. The problem is that if I add the parentheses it
> breaks the usage below due to the curly brackets. But the definition
> above is just so convenient and I couldn't find another neat solution so
> far. If you are concerned about that I can give it another try,
> otherwise I tend to just ignore checkpatch here.
OK maybe you can add a comment then?
> 
>>> +static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
>>> +{
>> can't we have the same LPI present in different interrupt translation
>> tables? I don't know it is a sensible setting but I did not succeed in
>> finding it was not possible.
> 
> Thanks to Marc I am happy (and relieved!) to point you to 6.1.1 LPI INTIDs:
> "The behavior of the GIC is UNPREDICTABLE if software:
> - Maps multiple EventID/DeviceID combinations to the same physical LPI
> INTID."
> 
> So I exercise the freedom of UNPREDICTABLE here ;-)

OK
> 
>>> +     struct its_device *device;
>>> +     struct its_itte *itte;
>>> +
>>> +     for_each_lpi(device, itte, kvm) {
>>> +             if (itte->lpi == lpi)
>>> +                     return itte;
>>> +     }
>>> +     return NULL;
>>> +}
>>> +
>>>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>>>
>>>  /* The distributor lock is held by the VGIC MMIO handler. */
>>> @@ -145,6 +163,59 @@ static bool handle_mmio_gits_idregs(struct kvm_vcpu *vcpu,
>>>       return false;
>>>  }
>>>
>>> +/*
>>> + * Find all enabled and pending LPIs and queue them into the list
>>> + * registers.
>>> + * The dist lock is held by the caller.
>>> + */
>>> +bool vits_queue_lpis(struct kvm_vcpu *vcpu)
>>> +{
>>> +     struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
>>> +     struct its_device *device;
>>> +     struct its_itte *itte;
>>> +     bool ret = true;
>>> +
>>> +     if (!vgic_has_its(vcpu->kvm))
>>> +             return true;
>>> +     if (!its->enabled || !vcpu->kvm->arch.vgic.lpis_enabled)
>>> +             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)
>>> +                     continue;
>>> +
>>> +             __clear_bit(vcpu->vcpu_id, itte->pending);
>>> +
>>> +             ret &= vgic_queue_irq(vcpu, 0, itte->lpi);
>> what if the vgic_queue_irq fails since no LR can be found, the
>> itte->pending was cleared so we forget that LPI? shouldn't we restore
>> the pending state in ITT? in vgic_queue_hwirq the state change only is
>> performed if the vgic_queue_irq succeeds
> 
> Of course you are right. I will just only clear the bit if the call
> succeeds.
> 
>>> +     }
>>> +
>>> +     spin_unlock(&its->lock);
>>> +     return ret;
>>> +}
>>> +
>>> +/* Called with the distributor lock held by the caller. */
>>> +void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi)
>> I was a bit confused by the name of the function, with regard to
>> existing vgic_unqueue_irqs which restores the states in accordance to
>> what we have in LR. Wouldn't it make sense to call it
>> vits_lpi_set_pending(vcpu, lpi) or something that looks more similar to
>> vgic_dist_irq_set_pending setter which I think it mirrors.
> 
> Well, vgic_unqueue_irqs() "move[s] pending/active IRQs from LRs to the
> distributor", this is what vits_unqueue_lpi() also does, just for one
> _single_ LPI instead of iterating over all LRs. Originally I planned to
> call vgic_unqueue_irqs on every guest exit, so this would have a more
> obvious match.
> Admittedly the function does not do much "unqueueing", as this is done
> in the caller, so I will think about the renaming part.
> 
>>> +{
>>> +     struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
>>> +     struct its_itte *itte;
>>> +
>>> +     spin_lock(&its->lock);
>>> +
>>> +     /* Find the right ITTE and put the pending state back in there */
>>> +     itte = find_itte_by_lpi(vcpu->kvm, lpi);
>>> +     if (itte)
>>> +             __set_bit(vcpu->vcpu_id, itte->pending);
>>> +
>>> +     spin_unlock(&its->lock);
>>> +}
>>> +
>>>  static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
>>>  {
>>>       return -ENODEV;
>>> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
>>> index 472a6d0..cc5d5ff 100644
>>> --- a/virt/kvm/arm/its-emul.h
>>> +++ b/virt/kvm/arm/its-emul.h
>>> @@ -33,4 +33,7 @@ void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>>>  int vits_init(struct kvm *kvm);
>>>  void vits_destroy(struct kvm *kvm);
>>>
>>> +bool vits_queue_lpis(struct kvm_vcpu *vcpu);
>>> +void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int irq);
>>> +
>>>  #endif
>>> diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
>>> index 49be3c3..4132c26 100644
>>> --- a/virt/kvm/arm/vgic-v3-emul.c
>>> +++ b/virt/kvm/arm/vgic-v3-emul.c
>>> @@ -948,6 +948,8 @@ void vgic_v3_init_emulation(struct kvm *kvm)
>>>       dist->vm_ops.init_model = vgic_v3_init_model;
>>>       dist->vm_ops.destroy_model = vgic_v3_destroy_model;
>>>       dist->vm_ops.map_resources = vgic_v3_map_resources;
>>> +     dist->vm_ops.queue_lpis = vits_queue_lpis;
>>> +     dist->vm_ops.unqueue_lpi = vits_unqueue_lpi;
>>>
>>>       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 49ee92b..9dfd094 100644
>>> --- a/virt/kvm/arm/vgic.c
>>> +++ b/virt/kvm/arm/vgic.c
>>> @@ -95,6 +95,20 @@ static bool queue_sgi(struct kvm_vcpu *vcpu, int irq)
>>>       return vcpu->kvm->arch.vgic.vm_ops.queue_sgi(vcpu, irq);
>>>  }
>>>
>>> +static bool vgic_queue_lpis(struct kvm_vcpu *vcpu)
>>> +{
>>> +     if (vcpu->kvm->arch.vgic.vm_ops.queue_lpis)
>>> +             return vcpu->kvm->arch.vgic.vm_ops.queue_lpis(vcpu);
>>> +     else
>>> +             return true;
>>> +}
>>> +
>>> +static void vgic_unqueue_lpi(struct kvm_vcpu *vcpu, int irq)
>>> +{
>>> +     if (vcpu->kvm->arch.vgic.vm_ops.unqueue_lpi)
>>> +             vcpu->kvm->arch.vgic.vm_ops.unqueue_lpi(vcpu, irq);
>>> +}
>>> +
>>>  int kvm_vgic_map_resources(struct kvm *kvm)
>>>  {
>>>       return kvm->arch.vgic.vm_ops.map_resources(kvm, vgic);
>>> @@ -1135,6 +1149,10 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
>>>       for_each_clear_bit(lr, elrsr_ptr, vgic->nr_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)) {
>>>                       vlr.state = 0;
>>>                       vgic_set_lr(vcpu, lr, vlr);
>>> @@ -1147,25 +1165,33 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
>>>  static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>>>                                int lr_nr, int sgi_source_id)
>>>  {
>>> +     struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>>       struct vgic_lr vlr;
>>>
>>>       vlr.state = 0;
>>>       vlr.irq = irq;
>>>       vlr.source = sgi_source_id;
>>>
>>> -     if (vgic_irq_is_active(vcpu, irq)) {
>>> -             vlr.state |= LR_STATE_ACTIVE;
>>> -             kvm_debug("Set active, clear distributor: 0x%x\n", vlr.state);
>>> -             vgic_irq_clear_active(vcpu, irq);
>>> -             vgic_update_state(vcpu->kvm);
>>> -     } else if (vgic_dist_irq_is_pending(vcpu, irq)) {
>>> -             vlr.state |= LR_STATE_PENDING;
>>> -             kvm_debug("Set pending: 0x%x\n", vlr.state);
>>> -     }
>>> -
>>> -     if (!vgic_irq_is_edge(vcpu, irq))
>>> -             vlr.state |= LR_EOI_INT;
>>> +     /* We care only about state for SGIs/PPIs/SPIs, not for LPIs */
>>> +     if (irq < dist->nr_irqs) {
>>> +             if (vgic_irq_is_active(vcpu, irq)) {
>>> +                     vlr.state |= LR_STATE_ACTIVE;
>>> +                     kvm_debug("Set active, clear distributor: 0x%x\n",
>>> +                               vlr.state);
>>> +                     vgic_irq_clear_active(vcpu, irq);
>>> +                     vgic_update_state(vcpu->kvm);
>>> +             } else if (vgic_dist_irq_is_pending(vcpu, irq)) {
>>> +                     vlr.state |= LR_STATE_PENDING;
>>> +                     kvm_debug("Set pending: 0x%x\n", vlr.state);
>>> +             }
>>>
>>> +             if (!vgic_irq_is_edge(vcpu, irq))
>>> +                     vlr.state |= LR_EOI_INT;
>>> +     } else {
>>> +             /* If this is an LPI, it can only be pending */
>>> +             if (irq >= 8192)
>>> +                     vlr.state |= LR_STATE_PENDING;
>>> +     }
>>>       vgic_set_lr(vcpu, lr_nr, vlr);
>>>       vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
>>>  }
>>> @@ -1177,7 +1203,6 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>>>   */
>>>  bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>>>  {
>>> -     struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>>       u64 elrsr = vgic_get_elrsr(vcpu);
>>>       unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
>>>       int lr;
>>> @@ -1185,7 +1210,6 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>>>       /* Sanitize the input... */
>>>       BUG_ON(sgi_source_id & ~7);
>>>       BUG_ON(sgi_source_id && irq >= VGIC_NR_SGIS);
>>> -     BUG_ON(irq >= dist->nr_irqs);
>> Is it safe to remove that check. What if it is attempted to inject an
>> SPI larger than supported. I think you should refine the check but not
>> remove it.
> 
> The check is now in vgic_queue_irq_to_lr (see above), where we
> differentiate between LPIs (>=8192) and SPIs (<dist->nr_irqs). Please
> correct me if I am wrong on this, but since we are not setting any state
> bits the vgic_set_lr() and vgic_sync_lr_elrsr() calls should be NOPs in
> this case, right?
Looks OK indeed.

Cheers

Eric
> I may re-add the explicit check here for the sake of clarity, though.
> 
>>>
>>>       kvm_debug("Queue IRQ%d\n", irq);
>>>
>>> @@ -1265,8 +1289,12 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>>>                       overflow = 1;
>>>       }
>>>
>>> -
>>> -
>>> +     /*
>>> +      * LPIs are not mapped in our bitmaps, so we leave the iteration
>>> +      * to the ITS emulation code.
>>> +      */
>>> +     if (!vgic_queue_lpis(vcpu))
>>> +             overflow = 1;
>>>
>>>  epilog:
>>>       if (overflow) {
>>> @@ -1387,6 +1415,16 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>>>       for_each_clear_bit(lr_nr, elrsr_ptr, vgic_cpu->nr_lr) {
>>>               vlr = vgic_get_lr(vcpu, lr_nr);
>>>
>>> +             /* LPIs are handled separately */
>>> +             if (vlr.irq >= 8192) {
>>> +                     /* We just need to take care about still pending LPIs */
>>> +                     if (vlr.state & LR_STATE_PENDING) {
>>> +                             vgic_unqueue_lpi(vcpu, vlr.irq);
>>> +                             pending = true;
>>> +                     }
>>> +                     continue;
>> don't we need to reset the LR & update elrsr?
> 
> Mmmh, interesting, I just wonder how it worked before. I will move most
> of the lower part into an else clause and call the LR maintainance code
> in both cases.
> 
> Cheers,
> Andre.
> 
>>> +             }
>>> +
>>>               BUG_ON(!(vlr.state & LR_STATE_MASK));
>>>               pending = true;
>>>
>>> @@ -1411,7 +1449,7 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>>>       }
>>>       vgic_update_state(vcpu->kvm);
>>>
>>> -     /* vgic_update_state would not cover only-active IRQs */
>>> +     /* vgic_update_state would not cover only-active IRQs or LPIs */
>>>       if (pending)
>>>               set_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu);
>>>  }
>>>
>>

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 12/15] KVM: arm64: sync LPI configuration and pending tables
  2015-08-25 15:27     ` Andre Przywara
@ 2015-08-31  9:47       ` Eric Auger
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Auger @ 2015-08-31  9:47 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/25/2015 05:27 PM, Andre Przywara wrote:
> Hi Eric,
> 
> On 14/08/15 12:58, Eric Auger wrote:
>> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>>> The LPI configuration and pending tables of the GICv3 LPIs are held
>>> in tables in (guest) memory. To achieve reasonable performance, we
>>> cache this data in our own data structures, so we need to sync those
>>> two views from time to time. This behaviour is well described in the
>>> GICv3 spec and is also exercised by hardware, so the sync points are
>>> well known.
>>>
>>> Provide functions that read the guest memory and store the
>>> information from the configuration and pending tables in the kernel.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>> would help to have change log between v1 -> v2 (valid for the whole series)
>>>  include/kvm/arm_vgic.h  |   2 +
>>>  virt/kvm/arm/its-emul.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/its-emul.h |   3 ++
>>>  3 files changed, 129 insertions(+)
>>>
>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>> index 2a67a10..323c33a 100644
>>> --- a/include/kvm/arm_vgic.h
>>> +++ b/include/kvm/arm_vgic.h
>>> @@ -167,6 +167,8 @@ struct vgic_its {
>>>  	int			cwriter;
>>>  	struct list_head	device_list;
>>>  	struct list_head	collection_list;
>>> +	/* memory used for buffering guest's memory */
>>> +	void			*buffer_page;
>>>  };
>>>  
>>>  struct vgic_dist {
>>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>>> index b9c40d7..05245cb 100644
>>> --- a/virt/kvm/arm/its-emul.c
>>> +++ b/virt/kvm/arm/its-emul.c
>>> @@ -50,6 +50,7 @@ struct its_itte {
>>>  	struct its_collection *collection;
>>>  	u32 lpi;
>>>  	u32 event_id;
>>> +	u8 priority;
>>>  	bool enabled;
>>>  	unsigned long *pending;
>>>  };
>>> @@ -70,8 +71,124 @@ static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
>>>  	return NULL;
>>>  }
>>>  
>>> +#define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
>>> +#define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
>>> +
>>> +/* stores the priority and enable bit for a given LPI */
>>> +static void update_lpi_config(struct kvm *kvm, struct its_itte *itte, u8 prop)
>>> +{
>>> +	itte->priority = LPI_PROP_PRIORITY(prop);
>>> +	itte->enabled  = LPI_PROP_ENABLE_BIT(prop);
>>> +}
>>> +
>>> +#define GIC_LPI_OFFSET 8192
>>> +
>>> +/* We scan the table in chunks the size of the smallest page size */
>> 4kB chunks?
> 
> Marc was complaining about this wording, I think. The rationale was that
> "4K" is already in the code and thus does not need to be repeated in the
> comment, whereas the comment should explain the meaning of the value.

understood

Eric
> 
>>> +#define CHUNK_SIZE 4096U
>>> +
>>>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>>>  
>>> +static int nr_idbits_propbase(u64 propbaser)
>>> +{
>>> +	int nr_idbits = (1U << (propbaser & 0x1f)) + 1;
>>> +
>>> +	return max(nr_idbits, INTERRUPT_ID_BITS_ITS);
>>> +}
>>> +
>>> +/*
>>> + * Scan the whole LPI configuration table and put the LPI configuration
>>> + * data in our own data structures. This relies on the LPI being
>>> + * mapped before.
>>> + */
>>> +static bool its_update_lpis_configuration(struct kvm *kvm)
>>> +{
>>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>>> +	u8 *prop = dist->its.buffer_page;
>>> +	u32 tsize;
>>> +	gpa_t propbase;
>>> +	int lpi = GIC_LPI_OFFSET;
>>> +	struct its_itte *itte;
>>> +	struct its_device *device;
>>> +	int ret;
>>> +
>>> +	propbase = BASER_BASE_ADDRESS(dist->propbaser);
>>> +	tsize = nr_idbits_propbase(dist->propbaser);
>>> +
>>> +	while (tsize > 0) {
>>> +		int chunksize = min(tsize, CHUNK_SIZE);
>>> +
>>> +		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
>> I think you still have the spin_lock issue  since if my understanding is
>> correct this is called from
>> vgic_handle_mmio_access/vcall_range_handler/gic_enable_lpis
>> where vgic_handle_mmio_access. Or does it take another path?
> 
> Well, it's (also) called on handling the INVALL command, but you are
> right that on that enable path the dist lock is held. I reckon that this
> init part isn't racy so that shouldn't be a problem (famous last words ;-).
> Let me see whether I can find a way to just drop the lock around the
> while loop.
> 
> Cheers,
> Andre.
> 
>>
>> Shouldn't we create a new kvm_io_device to avoid holding the dist lock?
>>
>> Eric

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 12/15] KVM: arm64: sync LPI configuration and pending tables
  2015-08-25 15:47       ` Andre Przywara
@ 2015-08-31  9:51         ` Eric Auger
  0 siblings, 0 replies; 69+ messages in thread
From: Eric Auger @ 2015-08-31  9:51 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/25/2015 05:47 PM, Andre Przywara wrote:
> Hi Eric,
> 
> On 14/08/15 13:35, Eric Auger wrote:
>> On 08/14/2015 01:58 PM, Eric Auger wrote:
>>> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>>>> The LPI configuration and pending tables of the GICv3 LPIs are held
>>>> in tables in (guest) memory. To achieve reasonable performance, we
>>>> cache this data in our own data structures, so we need to sync those
>>>> two views from time to time. This behaviour is well described in the
>>>> GICv3 spec and is also exercised by hardware, so the sync points are
>>>> well known.
>>>>
>>>> Provide functions that read the guest memory and store the
>>>> information from the configuration and pending tables in the kernel.
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>> would help to have change log between v1 -> v2 (valid for the whole series)
>>>>  include/kvm/arm_vgic.h  |   2 +
>>>>  virt/kvm/arm/its-emul.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/its-emul.h |   3 ++
>>>>  3 files changed, 129 insertions(+)
>>>>
>>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>>> index 2a67a10..323c33a 100644
>>>> --- a/include/kvm/arm_vgic.h
>>>> +++ b/include/kvm/arm_vgic.h
>>>> @@ -167,6 +167,8 @@ struct vgic_its {
>>>>  	int			cwriter;
>>>>  	struct list_head	device_list;
>>>>  	struct list_head	collection_list;
>>>> +	/* memory used for buffering guest's memory */
>>>> +	void			*buffer_page;
>>>>  };
>>>>  
>>>>  struct vgic_dist {
>>>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>>>> index b9c40d7..05245cb 100644
>>>> --- a/virt/kvm/arm/its-emul.c
>>>> +++ b/virt/kvm/arm/its-emul.c
>>>> @@ -50,6 +50,7 @@ struct its_itte {
>>>>  	struct its_collection *collection;
>>>>  	u32 lpi;
>>>>  	u32 event_id;
>>>> +	u8 priority;
>>>>  	bool enabled;
>>>>  	unsigned long *pending;
>>>>  };
>>>> @@ -70,8 +71,124 @@ static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
>>>>  	return NULL;
>>>>  }
>>>>  
>>>> +#define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
>>>> +#define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
>>>> +
>>>> +/* stores the priority and enable bit for a given LPI */
>>>> +static void update_lpi_config(struct kvm *kvm, struct its_itte *itte, u8 prop)
>>>> +{
>>>> +	itte->priority = LPI_PROP_PRIORITY(prop);
>>>> +	itte->enabled  = LPI_PROP_ENABLE_BIT(prop);
>>>> +}
>>>> +
>>>> +#define GIC_LPI_OFFSET 8192
>>>> +
>>>> +/* We scan the table in chunks the size of the smallest page size */
>>> 4kB chunks?
>>>> +#define CHUNK_SIZE 4096U
>>>> +
>>>>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
>>>>  
>>>> +static int nr_idbits_propbase(u64 propbaser)
>>>> +{
>>>> +	int nr_idbits = (1U << (propbaser & 0x1f)) + 1;
>>>> +
>>>> +	return max(nr_idbits, INTERRUPT_ID_BITS_ITS);
>>>> +}
>>>> +
>>>> +/*
>>>> + * Scan the whole LPI configuration table and put the LPI configuration
>>>> + * data in our own data structures. This relies on the LPI being
>>>> + * mapped before.
>>>> + */
>>>> +static bool its_update_lpis_configuration(struct kvm *kvm)
>>>> +{
>>>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>>>> +	u8 *prop = dist->its.buffer_page;
>>>> +	u32 tsize;
>>>> +	gpa_t propbase;
>>>> +	int lpi = GIC_LPI_OFFSET;
>>>> +	struct its_itte *itte;
>>>> +	struct its_device *device;
>>>> +	int ret;
>>>> +
>>>> +	propbase = BASER_BASE_ADDRESS(dist->propbaser);
>>>> +	tsize = nr_idbits_propbase(dist->propbaser);
>>>> +
>>>> +	while (tsize > 0) {
>>>> +		int chunksize = min(tsize, CHUNK_SIZE);
>>>> +
>>>> +		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
>>> I think you still have the spin_lock issue  since if my understanding is
>>> correct this is called from
>>> vgic_handle_mmio_access/vcall_range_handler/gic_enable_lpis
>>> where vgic_handle_mmio_access. Or does it take another path?
>>>
>>> Shouldn't we create a new kvm_io_device to avoid holding the dist lock?
>>
>> Sorry I forgot it was the case already. But currently we always register
>> the same io ops (registration entry point being
>> vgic_register_kvm_io_dev) and maybe we should have separate dispatcher
>> function for dist, redit and its?
> 
> What would be the idea behind it? To have separate locks for each? I
> don't think that will work, as some ITS functions are called from GICv3
> register handler functions which manipulate members of the distributor
> structure.

Yes it was the idea.

 So I am more in favour of dropping the dist lock in these
> cases before handing off execution to ITS specific functions.

OK. Let's see how the refactoring looks like then

Cheers

Eric
> 
> Cheers,
> Andre.
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-08-31  8:42       ` Eric Auger
@ 2015-09-02  9:00         ` Andre Przywara
  0 siblings, 0 replies; 69+ messages in thread
From: Andre Przywara @ 2015-09-02  9:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 31/08/15 09:42, Eric Auger wrote:
> On 08/24/2015 06:33 PM, Andre Przywara wrote:

Salut Eric,

...

>>>> @@ -1126,9 +1124,9 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
>>>>   */
>>>>  bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>>>>  {
>>>> -   struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>>>     struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>>> -   struct vgic_lr vlr;
>>>> +   u64 elrsr = vgic_get_elrsr(vcpu);
>>>> +   unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
>>>>     int lr;
>>>>
>>>>     /* Sanitize the input... */
>>>> @@ -1138,42 +1136,20 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>>>>
>>>>     kvm_debug("Queue IRQ%d\n", irq);
>>>>
>>>> -   lr = vgic_cpu->vgic_irq_lr_map[irq];
>>>> -
>>>> -   /* Do we have an active interrupt for the same CPUID? */
>>>> -   if (lr != LR_EMPTY) {
>>>> -           vlr = vgic_get_lr(vcpu, lr);
>>>> -           if (vlr.source == sgi_source_id) {
>>>> -                   kvm_debug("LR%d piggyback for IRQ%d\n", lr, vlr.irq);
>>>> -                   BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
>>>> -                   vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
>>>> -                   return true;
>>>> -           }
>>>> -   }
>>>> +   lr = find_first_bit(elrsr_ptr, vgic->nr_lr);
>>>>
>>>> -   /* Try to use another LR for this interrupt */
>>>> -   lr = find_first_zero_bit((unsigned long *)vgic_cpu->lr_used,
>>>> -                          vgic->nr_lr);
>>>>     if (lr >= vgic->nr_lr)
>>>>             return false;
>>>>
>>>>     kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id);
>>>> -   vgic_cpu->vgic_irq_lr_map[irq] = lr;
>>>> -   set_bit(lr, vgic_cpu->lr_used);
>>>>
>>>> -   vlr.irq = irq;
>>>> -   vlr.source = sgi_source_id;
>>>> -   vlr.state = 0;
>>>> -   vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
>>>> +   vgic_queue_irq_to_lr(vcpu, irq, lr, sgi_source_id);
>>>>
>>>>     return true;
>>>>  }
>>>>
>>>>  static bool vgic_queue_hwirq(struct kvm_vcpu *vcpu, int irq)
>>>>  {
>>>> -   if (!vgic_can_sample_irq(vcpu, irq))
>>>> -           return true; /* level interrupt, already queued */
>>>> -
>>> I think that change needs to be introduced in a separate patch as the
>>> other one mentioned above and justified since it affects the state machine.
>>
>> But this change is dependent on this patch: it will not work without
>> this patch and this patch will not work without that change.
>> So the idea is that on returning from the guest we now harvest all
>> _used_ LRs by copying their state back into the distributor. The
>> previous behaviour was to just check _unused_ LRs for completed IRQs.
>> So now all IRQs need to be re-inserted into the LRs before the next
>> guest run, that's why we have to remove the test which skipped this for
>> IRQs where the code knew that they were still in the LRs.
>> Does that make sense?
> In level sensitive case, what if the IRQ'LR state was active. LR was
> kept intact. IRQ is queued. With previous code we wouldn't inject a new
> IRQ. Here aren't we going to inject it?

Effectively we only inject _pending_ IRQs: I was going forth and back
through the current code and couldn't find a place where we actually
make use of any active-only interrupt - the only exception being
migration, where we explicitly iterate through all LRs again and pick up
active-only IRQs as well. We never set the active state except there.

So I decided to keep only-active IRQs in the LRs and do not propagate
them back into the emulated distributor state. One reason is that we
don't use it, which makes the code look silly and secondly we avoid the
issue you described above.

> In the sync when you move the IRQ from the LR reg to the state variable,
> shouldn't you reset the queued state for level sensitive case? In such a
> case I think you could keep that check.

We keep them as "queued" in our emulation until they become inactive and
we clear the queued bit in the EOI handler.

Admittedly this whole approach is not obvious and it's perfectly
possible that I missed something. So please can you check and confirm my
assumptions above?

Merci,
Andr?

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation
  2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
                   ` (15 preceding siblings ...)
  2015-07-15 12:02 ` [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Pavel Fedin
@ 2015-09-24 11:18 ` Pavel Fedin
  2015-09-24 11:35   ` Andre Przywara
  16 siblings, 1 reply; 69+ messages in thread
From: Pavel Fedin @ 2015-09-24 11:18 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello Andre and others!

 How are things going? I see the last message in thread something like 1 month old, then silence...
 Our project relies on this feature, any assistance needed?

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation
  2015-09-24 11:18 ` Pavel Fedin
@ 2015-09-24 11:35   ` Andre Przywara
  0 siblings, 0 replies; 69+ messages in thread
From: Andre Przywara @ 2015-09-24 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Pavel,

On 24/09/15 12:18, Pavel Fedin wrote:
>  Hello Andre and others!
> 
>  How are things going? I see the last message in thread something like 1 month old, then silence...
>  Our project relies on this feature, any assistance needed?

I am about to make it work on top of Christoffer's latest arch timer
rework patches, which means I need to rewrite most of patch 1. Currently
that boots, but hangs as soon as I put some load on it. Finding the
reason for this is a bit tedious at the moment.
I have addressed the comments from the list on the other patches, so
ideally I can send a new revision as soon as I fixed that bug in the
first patch.

Cheers,
Andre.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 09/15] KVM: arm64: implement basic ITS register handlers
  2015-07-10 14:21 ` [PATCH v2 09/15] KVM: arm64: implement basic ITS register handlers Andre Przywara
  2015-08-13 15:25   ` Eric Auger
@ 2015-10-02  7:51   ` Pavel Fedin
  1 sibling, 0 replies; 69+ messages in thread
From: Pavel Fedin @ 2015-10-02  7:51 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello!

 Long time has passed, but i started working on live migration of this thing, and found some more
problems.

> @@ -117,9 +305,26 @@ int vits_init(struct kvm *kvm)
>  	struct vgic_dist *dist = &kvm->arch.vgic;
>  	struct vgic_its *its = &dist->its;
> 
> +	dist->pendbaser = kmalloc(sizeof(u64) * dist->nr_cpus, GFP_KERNEL);
> +	if (!dist->pendbaser)
> +		return -ENOMEM;
> +
>  	spin_lock_init(&its->lock);
> 
>  	its->enabled = false;
> 
>  	return -ENXIO;
>  }
> +

 vits_init() allocates table for per-CPU pendbaser values. However, it is called from within
vgicv3_map_resources(), which is in turn called upon first vCPU run. This is too late, because in
case of live migration we would first want to set up all registers from within the userspace. But,
when i start doing this, i crash in handle_mmio_pendbaser_redist(), because of dist->pendbaser being
NULL.
 The solution is to split the function up. I moved vgic_register_kvm_io_dev() (introduced by later
patch) to vits_map_resources(), which is now called where vits_init() originally was. My new
vits_init() (which is made reentrant by checking for dist->pendbaser != NULL) is now called from
within two places:
 a) vits_map_resources()
 b) handle_mmio_pendbaser_redist()

 Therefore, all allocations happen either on first vCPU run, or on first PENDBASER access, whatever
comes first. An alternative is to do allocations during KVM_DEV_ARM_VGIC_CTRL_INIT.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-07-10 14:21 ` [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor Andre Przywara
  2015-08-12  9:01   ` Eric Auger
@ 2015-10-02  9:55   ` Pavel Fedin
  2015-10-02 10:32     ` Andre Przywara
  1 sibling, 1 reply; 69+ messages in thread
From: Pavel Fedin @ 2015-10-02  9:55 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello! One more concern.

> Currently we track which IRQ has been mapped to which VGIC list
> register and also have to synchronize both. We used to do this
> to hold some extra state (for instance the active bit).
> It turns out that this extra state in the LRs is no longer needed and
> this extra tracking causes some pain later.

 Returning to the beginning, can you explain, what kind of pain exactly does it bring?
 For some reasons here i had to keep all this tracking mechanism, and modified your patchset. I see
no significant problems, except memory usage. I have to allocate vgic_irq_lr_map large enough to
hold indexes up to 16384, and indexes from dist->nr_irqs to 8192 appear to be not used.
 Since the map itself is actually used only for piggy-back optimization, it is possible to easily
get rid of it using for_each_set_bit(lr, vgic_cpu->lr_used, vgic->nr_lr) iteration instead. The rest
of mechanism will work as it is, there's no need to remove the state tracking bitmap and
optimization itself.
 I am currently testing this approach and preparing my alternative patch for upstreaming.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-10-02  9:55   ` Pavel Fedin
@ 2015-10-02 10:32     ` Andre Przywara
  2015-10-02 10:39       ` Pavel Fedin
  2015-10-02 12:39       ` Pavel Fedin
  0 siblings, 2 replies; 69+ messages in thread
From: Andre Przywara @ 2015-10-02 10:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Pavel,

On 02/10/15 10:55, Pavel Fedin wrote:
>  Hello! One more concern.
> 
>> Currently we track which IRQ has been mapped to which VGIC list
>> register and also have to synchronize both. We used to do this
>> to hold some extra state (for instance the active bit).
>> It turns out that this extra state in the LRs is no longer needed and
>> this extra tracking causes some pain later.
> 
>  Returning to the beginning, can you explain, what kind of pain exactly does it bring?
>  For some reasons here i had to keep all this tracking mechanism, and modified your patchset. I see
> no significant problems, except memory usage. I have to allocate vgic_irq_lr_map large enough to
> hold indexes up to 16384, and indexes from dist->nr_irqs to 8192 appear to be not used.

Yes, this was the main problem I was concerned about. Actually not so
much about memory usage really, but more about the idea of pushing the
concept of bitmaps beyond the point where it is a reasonable data
structure to use.
I briefly thought about extending the bitmaps, but that sounded like a
hack to me.
For instance how did you come up with that 16384? LPIs could actually be
much bigger (in fact the emulation currently support up to 64k).
In my opinion removing that tracking mechanism is actually a good idea.
Most implementations actually have only _four_ list registers and since
we keep them shadowed in our KVM data structure, iterating over all of
them is not really painful.

>  Since the map itself is actually used only for piggy-back optimization, it is possible to easily
> get rid of it using for_each_set_bit(lr, vgic_cpu->lr_used, vgic->nr_lr) iteration instead.

Can't you use the ELRSR bitmap instead? The idea of lr_used sounds like
a moot optimization to me.

Cheers,
Andre.

> The rest
> of mechanism will work as it is, there's no need to remove the state tracking bitmap and
> optimization itself.
>  I am currently testing this approach and preparing my alternative patch for upstreaming.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-10-02 10:32     ` Andre Przywara
@ 2015-10-02 10:39       ` Pavel Fedin
  2015-10-02 12:39       ` Pavel Fedin
  1 sibling, 0 replies; 69+ messages in thread
From: Pavel Fedin @ 2015-10-02 10:39 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello!

> For instance how did you come up with that 16384? LPIs could actually be
> much bigger (in fact the emulation currently support up to 64k).

 Well, read "at least 16384". I actually don't remember the exact value you've put in.

> >  Since the map itself is actually used only for piggy-back optimization, it is possible to
> easily
> > get rid of it using for_each_set_bit(lr, vgic_cpu->lr_used, vgic->nr_lr) iteration instead.
> 
> Can't you use the ELRSR bitmap instead? The idea of lr_used sounds like
> a moot optimization to me.

 I'll take a look. You seem to be right, lr_used became a direct (well, inverted) copy of elrsr
after full elrsr synchronization was introduced long time ago. It's just current code relying on
lr_used everywhere.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-10-02 10:32     ` Andre Przywara
  2015-10-02 10:39       ` Pavel Fedin
@ 2015-10-02 12:39       ` Pavel Fedin
  2015-10-02 12:49         ` Andre Przywara
  1 sibling, 1 reply; 69+ messages in thread
From: Pavel Fedin @ 2015-10-02 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello!

> Can't you use the ELRSR bitmap instead? The idea of lr_used sounds like
> a moot optimization to me.

 This perfectly works on 4.2, but will break HW interrupt forwarding on 4.3. If you look at 4.3
__kvm_vgic_sync_hwstate(), you'll notice that for HW interrupts lr_used and elrsr_ptr will diverge
at this point, and this function actually brings them into sync. And it relies on lr_used for the
loop to operate correctly (no idea why we use "for" loop here with extra check instead of
"for_each_set_bit(lr, vgic_cpu->lr_used, vgic->nr_lr)", looks stupid to me).

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-10-02 12:39       ` Pavel Fedin
@ 2015-10-02 12:49         ` Andre Przywara
  0 siblings, 0 replies; 69+ messages in thread
From: Andre Przywara @ 2015-10-02 12:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Pavel,

On 02/10/15 13:39, Pavel Fedin wrote:
>  Hello!
> 
>> Can't you use the ELRSR bitmap instead? The idea of lr_used sounds like
>> a moot optimization to me.
> 
>  This perfectly works on 4.2, but will break HW interrupt forwarding on 4.3. If you look at 4.3
> __kvm_vgic_sync_hwstate(), you'll notice that for HW interrupts lr_used and elrsr_ptr will diverge
> at this point, and this function actually brings them into sync. And it relies on lr_used for the
> loop to operate correctly (no idea why we use "for" loop here with extra check instead of
> "for_each_set_bit(lr, vgic_cpu->lr_used, vgic->nr_lr)", looks stupid to me).

I know, because I have reworked my patch lately to work on top of 4.3-rc
and Christoffer's timer rework series. I have something which "works
now"(TM), but wanted to wait for Christoffer's respin to send out.
I will send you this new version this as a sneak preview in private,
maybe that helps.

Cheers,
Andre.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 11/15] KVM: arm64: handle pending bit for LPIs in ITS emulation
  2015-07-10 14:21 ` [PATCH v2 11/15] KVM: arm64: handle pending bit for LPIs in ITS emulation Andre Przywara
  2015-08-14 11:58   ` Eric Auger
@ 2015-10-07  8:39   ` Pavel Fedin
  2015-10-07 19:53     ` Christoffer Dall
  1 sibling, 1 reply; 69+ messages in thread
From: Pavel Fedin @ 2015-10-07  8:39 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello!

> +/* Called with the distributor lock held by the caller. */
> +void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi)
> +{
> +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> +	struct its_itte *itte;
> +
> +	spin_lock(&its->lock);
> +
> +	/* Find the right ITTE and put the pending state back in there */
> +	itte = find_itte_by_lpi(vcpu->kvm, lpi);
> +	if (itte)
> +		__set_bit(vcpu->vcpu_id, itte->pending);
> +
> +	spin_unlock(&its->lock);
> +}

 I am working on implementing live migration for the ITS. And here i have one fundamental problem.
vits_unqueue_lpi() processes only PENDING state. And looks like this corresponds to the HW
implementation, which has only bitwise pending table. But, in terms of migration, we can actually
have LPI in active state, while it's being processed.
 The question is - how can we handle it? Should we have one more bitwise table for active LPIs, or
is it enough to remember only a single, currently active LPI? Can LPIs be preempted on a real
hardware, or not?

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 13/15] KVM: arm64: implement ITS command queue command handlers
  2015-08-17 13:33   ` Eric Auger
@ 2015-10-07 14:54     ` Andre Przywara
  0 siblings, 0 replies; 69+ messages in thread
From: Andre Przywara @ 2015-10-07 14:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

thanks a lot for your comments. I just found this email, which seemed to
have been crushed between my holidays and KVM forum.
I tried to address your concerns in my new revision, some have become
obsolete due to the reworked locking.
So I refrain from answering in detail here, since some code has changed
in v3 and I don't really want to talk about the old version anymore ;-)

If you care I can try to answer on your concerns in the new v3 context,
but you may want to take a look at the new patch anyway.

Cheers,
Andre.

On 17/08/15 14:33, Eric Auger wrote:
> On 07/10/2015 04:21 PM, Andre Przywara wrote:
>> The connection between a device, an event ID, the LPI number and the
>> allocated CPU is stored in in-memory tables in a GICv3, but their
>> format is not specified by the spec. Instead software uses a command
>> queue in a ring buffer to let the ITS implementation use their own
>> format.
>> Implement handlers for the various ITS commands and let them store
>> the requested relation into our own data structures.
>> To avoid kmallocs inside the ITS spinlock, we preallocate possibly
>> needed memory outside of the lock and free that if it turns out to
>> be not needed (mostly error handling).
> still dist lock ...?
>> Error handling is very basic at this point, as we don't have a good
>> way of communicating errors to the guest (usually a SError).
>> The INT command handler is missing at this point, as we gain the
>> capability of actually injecting MSIs into the guest only later on.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/linux/irqchip/arm-gic-v3.h |   5 +-
>>  virt/kvm/arm/its-emul.c            | 497 ++++++++++++++++++++++++++++++++++++-
>>  virt/kvm/arm/its-emul.h            |  11 +
>>  3 files changed, 511 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index 0b450c7..80db4f6 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -253,7 +253,10 @@
>>   */
>>  #define GITS_CMD_MAPD			0x08
>>  #define GITS_CMD_MAPC			0x09
>> -#define GITS_CMD_MAPVI			0x0a
>> +#define GITS_CMD_MAPTI			0x0a
>> +/* older GIC documentation used MAPVI for this command */
>> +#define GITS_CMD_MAPVI			GITS_CMD_MAPTI
>> +#define GITS_CMD_MAPI			0x0b
>>  #define GITS_CMD_MOVI			0x01
>>  #define GITS_CMD_DISCARD		0x0f
>>  #define GITS_CMD_INV			0x0c
>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>> index 05245cb..89534c6 100644
>> --- a/virt/kvm/arm/its-emul.c
>> +++ b/virt/kvm/arm/its-emul.c
>> @@ -22,6 +22,7 @@
>>  #include <linux/kvm_host.h>
>>  #include <linux/interrupt.h>
>>  #include <linux/list.h>
>> +#include <linux/slab.h>
>>  
>>  #include <linux/irqchip/arm-gic-v3.h>
>>  #include <kvm/arm_vgic.h>
>> @@ -55,6 +56,34 @@ struct its_itte {
>>  	unsigned long *pending;
>>  };
>>  
>> +static struct its_device *find_its_device(struct kvm *kvm, u32 device_id)
>> +{
>> +	struct vgic_its *its = &kvm->arch.vgic.its;
>> +	struct its_device *device;
>> +
>> +	list_for_each_entry(device, &its->device_list, dev_list)
>> +		if (device_id == device->device_id)
>> +			return device;
>> +
>> +	return NULL;
>> +}
>> +
>> +static struct its_itte *find_itte(struct kvm *kvm, u32 device_id, u32 event_id)
>> +{
>> +	struct its_device *device;
>> +	struct its_itte *itte;
>> +
>> +	device = find_its_device(kvm, device_id);
>> +	if (device == NULL)
>> +		return NULL;
>> +
>> +	list_for_each_entry(itte, &device->itt, itte_list)
>> +		if (itte->event_id == event_id)
>> +			return itte;
>> +
>> +	return NULL;
>> +}
>> +
>>  #define for_each_lpi(dev, itte, kvm) \
>>  	list_for_each_entry(dev, &(kvm)->arch.vgic.its.device_list, dev_list) \
>>  		list_for_each_entry(itte, &(dev)->itt, itte_list)
>> @@ -71,6 +100,19 @@ static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi)
>>  	return NULL;
>>  }
>>  
>> +static struct its_collection *find_collection(struct kvm *kvm, int coll_id)
>> +{
>> +	struct its_collection *collection;
>> +
>> +	list_for_each_entry(collection, &kvm->arch.vgic.its.collection_list,
>> +			    coll_list) {
>> +		if (coll_id == collection->collection_id)
>> +			return collection;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>>  #define LPI_PROP_ENABLE_BIT(p)	((p) & LPI_PROP_ENABLED)
>>  #define LPI_PROP_PRIORITY(p)	((p) & 0xfc)
>>  
>> @@ -333,9 +375,461 @@ void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi)
>>  	spin_unlock(&its->lock);
>>  }
>>  
>> +static u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
>> +{
>> +	return (le64_to_cpu(its_cmd[word]) >> shift) & (BIT_ULL(size) - 1);
>> +}
>> +
>> +#define its_cmd_get_command(cmd)	its_cmd_mask_field(cmd, 0,  0,  8)
>> +#define its_cmd_get_deviceid(cmd)	its_cmd_mask_field(cmd, 0, 32, 32)
>> +#define its_cmd_get_id(cmd)		its_cmd_mask_field(cmd, 1,  0, 32)
>> +#define its_cmd_get_physical_id(cmd)	its_cmd_mask_field(cmd, 1, 32, 32)
>> +#define its_cmd_get_collection(cmd)	its_cmd_mask_field(cmd, 2,  0, 16)
>> +#define its_cmd_get_target_addr(cmd)	its_cmd_mask_field(cmd, 2, 16, 32)
>> +#define its_cmd_get_validbit(cmd)	its_cmd_mask_field(cmd, 2, 63,  1)
>> +
>> +/* The DISCARD command frees an Interrupt Translation Table Entry (ITTE). */
>> +static int vits_cmd_handle_discard(struct kvm *kvm, u64 *its_cmd)
>> +{
>> +	struct vgic_its *its = &kvm->arch.vgic.its;
>> +	u32 device_id;
>> +	u32 event_id;
>> +	struct its_itte *itte;
>> +	int ret = 0;
>> +
>> +	device_id = its_cmd_get_deviceid(its_cmd);
>> +	event_id = its_cmd_get_id(its_cmd);
>> +
>> +	spin_lock(&its->lock);
>> +	itte = find_itte(kvm, device_id, event_id);
>> +	if (!itte || !itte->collection) {
>> +		ret = E_ITS_DISCARD_UNMAPPED_INTERRUPT;
>> +		goto out_unlock;
>> +	}
>> +
>> +	__clear_bit(itte->collection->target_addr, itte->pending);
> no use since the itte is deleted afterwards?
>> +
>> +	list_del(&itte->itte_list);
> However what about the deletion of the pending field? May be worth
> introducing a function to delete an itte (called several times)
>> +	kfree(itte);
>> +out_unlock:
>> +	spin_unlock(&its->lock);
>> +	return ret;
>> +}
>> +
>> +/* The MOVI command moves an ITTE to a different collection. */
>> +static int vits_cmd_handle_movi(struct kvm *kvm, u64 *its_cmd)
>> +{
>> +	struct vgic_its *its = &kvm->arch.vgic.its;
>> +	u32 device_id = its_cmd_get_deviceid(its_cmd);
>> +	u32 event_id = its_cmd_get_id(its_cmd);
>> +	u32 coll_id = its_cmd_get_collection(its_cmd);
>> +	struct its_itte *itte;
>> +	struct its_collection *collection;
>> +	int ret;
>> +
>> +	spin_lock(&its->lock);
>> +	itte = find_itte(kvm, device_id, event_id);
>> +	if (!itte) {
>> +		ret = E_ITS_MOVI_UNMAPPED_INTERRUPT;
>> +		goto out_unlock;
>> +	}
>> +	if (!itte->collection) {
>> +		ret = E_ITS_MOVI_UNMAPPED_COLLECTION;
>> +		goto out_unlock;
>> +	}
>> +
>> +	collection = find_collection(kvm, coll_id);
>> +	if (!collection) {
>> +		ret = E_ITS_MOVI_UNMAPPED_COLLECTION;
>> +		goto out_unlock;
>> +	}
>> +
>> +	if (test_and_clear_bit(itte->collection->target_addr, itte->pending))
>> +		__set_bit(collection->target_addr, itte->pending);
> Don't you think we should make sure target_addr is property set on both
> source & destination collection (MAPC with valid bit). Typically the
> user could MAPI and then call this. This would encourage to add a valid
> bit in the collection struct to tell the target_addr is set.
>> +
>> +	itte->collection = collection;
>> +out_unlock:
>> +	spin_unlock(&its->lock);
>> +	return ret;
>> +}
>> +
>> +static void vits_init_collection(struct kvm *kvm,
>> +				 struct its_collection *collection,
>> +				 u32 coll_id)
>> +{
>> +	collection->collection_id = coll_id;
>> +
>> +	list_add_tail(&collection->coll_list,
>> +		&kvm->arch.vgic.its.collection_list);
>> +}
>> +
>> +/* The MAPTI and MAPI commands map LPIs to ITTEs. */
>> +static int vits_cmd_handle_mapi(struct kvm *kvm, u64 *its_cmd, u8 cmd)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +	u32 device_id = its_cmd_get_deviceid(its_cmd);
>> +	u32 event_id = its_cmd_get_id(its_cmd);
>> +	u32 coll_id = its_cmd_get_collection(its_cmd);
>> +	struct its_itte *itte, *new_itte;
>> +	struct its_device *device;
>> +	struct its_collection *collection, *new_coll;
>> +	int lpi_nr;
>> +	int ret = 0;
>> +
>> +	/* Preallocate possibly needed memory here outside of the lock */
>> +	new_coll = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
>> +	new_itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
>> +	if (new_itte)
>> +		new_itte->pending = kcalloc(BITS_TO_LONGS(dist->nr_cpus),
>> +					    sizeof(long), GFP_KERNEL);
>> +
>> +	spin_lock(&dist->its.lock);
>> +
>> +	device = find_its_device(kvm, device_id);
>> +	if (!device) {
>> +		ret = E_ITS_MAPTI_UNMAPPED_DEVICE;
>> +		goto out_unlock;
>> +	}
>> +
>> +	collection = find_collection(kvm, coll_id);
>> +	if (!collection && !new_coll) {
>> +		ret = -ENOMEM;
>> +		goto out_unlock;
>> +	}
>> +
>> +	if (cmd == GITS_CMD_MAPTI)
>> +		lpi_nr = its_cmd_get_physical_id(its_cmd);
>> +	else
>> +		lpi_nr = event_id;
>> +	if (lpi_nr < GIC_LPI_OFFSET ||
>> +	    lpi_nr >= nr_idbits_propbase(dist->propbaser)) {
>> +		ret = E_ITS_MAPTI_PHYSICALID_OOR;
>> +		goto out_unlock;
>> +	}
>> +
>> +	itte = find_itte(kvm, device_id, event_id);
>> +	if (!itte) {
>> +		if (!new_itte || !new_itte->pending) {
>> +			ret = -ENOMEM;
>> +			goto out_unlock;
>> +		}
>> +		itte = new_itte;
>> +
>> +		itte->event_id	= event_id;
>> +		list_add_tail(&itte->itte_list, &device->itt);
>> +	} else {
>> +		if (new_itte)
>> +			kfree(new_itte->pending);
>> +		kfree(new_itte);
>> +	}
>> +
>> +	if (!collection) {
>> +		collection = new_coll;
> need to handle the case where new_coll is null which would cause a crash
> in init_collection
>> +		vits_init_collection(kvm, collection, coll_id);
>> +	} else {
>> +		kfree(new_coll);
>> +	}
>> +
>> +	itte->collection = collection;
>> +	itte->lpi = lpi_nr;
>> +
>> +out_unlock:
>> +	spin_unlock(&dist->its.lock);
>> +	if (ret) {
>> +		kfree(new_coll);
>> +		if (new_itte)
>> +			kfree(new_itte->pending);
>> +		kfree(new_itte);
>> +	}
>> +	return ret;
>> +}
>> +
>> +static void vits_unmap_device(struct kvm *kvm, struct its_device *device)
>> +{
>> +	struct its_itte *itte, *temp;
>> +
>> +	/*
>> +	 * The spec says that unmapping a device with still valid
>> +	 * ITTEs associated is UNPREDICTABLE. We remove all ITTEs,
>> +	 * since we cannot leave the memory unreferenced.
>> +	 */
>> +	list_for_each_entry_safe(itte, temp, &device->itt, itte_list) {
>> +		list_del(&itte->itte_list);
> deletion of itte->pending
>> +		kfree(itte);
>> +	}
>> +
>> +	list_del(&device->dev_list);
>> +	kfree(device);
>> +}
>> +
>> +/* The MAPD command maps device IDs to Interrupt Translation Tables (ITTs). */
> or unmaps
>> +static int vits_cmd_handle_mapd(struct kvm *kvm, u64 *its_cmd)
>> +{
>> +	struct vgic_its *its = &kvm->arch.vgic.its;
>> +	bool valid = its_cmd_get_validbit(its_cmd);
>> +	u32 device_id = its_cmd_get_deviceid(its_cmd);
>> +	struct its_device *device, *new_device = NULL;
>> +
>> +	/* We preallocate memory outside of the lock here */
>> +	if (valid) {
>> +		new_device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
>> +		if (!new_device)
>> +			return -ENOMEM;
>> +	}
>> +
>> +	spin_lock(&its->lock);
>> +
>> +	device = find_its_device(kvm, device_id);
>> +	if (device)
> logically valid should be false too else that's an error?
>> +		vits_unmap_device(kvm, device);
>> +
>> +	/*
>> +	 * The spec does not say whether unmapping a not-mapped device
>> +	 * is an error, so we are done in any case.
>> +	 */
>> +	if (!valid)
>> +		goto out_unlock;
>> +
>> +	device = new_device;
>> +
>> +	device->device_id = device_id;
>> +	INIT_LIST_HEAD(&device->itt);
>> +
>> +	list_add_tail(&device->dev_list,
>> +		      &kvm->arch.vgic.its.device_list);
>> +
>> +out_unlock:
>> +	spin_unlock(&its->lock);
>> +	return 0;
>> +}
>> +
>> +/* The MAPC command maps collection IDs to redistributors. */
>> +static int vits_cmd_handle_mapc(struct kvm *kvm, u64 *its_cmd)
>> +{
>> +	struct vgic_its *its = &kvm->arch.vgic.its;
>> +	u16 coll_id;
>> +	u32 target_addr;
>> +	struct its_collection *collection, *new_coll = NULL;
>> +	bool valid;
>> +
>> +	valid = its_cmd_get_validbit(its_cmd);
>> +	coll_id = its_cmd_get_collection(its_cmd);
>> +	target_addr = its_cmd_get_target_addr(its_cmd);
>> +
>> +	if (target_addr >= atomic_read(&kvm->online_vcpus))
>> +		return E_ITS_MAPC_PROCNUM_OOR;
>> +
>> +	/* We preallocate memory outside of the lock here */
>> +	if (valid) {
>> +		new_coll = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
>> +		if (!new_coll)
>> +			return -ENOMEM;
>> +	}
>> +
>> +	spin_lock(&its->lock);
>> +	collection = find_collection(kvm, coll_id);
>> +
>> +	if (!valid) {
>> +		struct its_device *device;
>> +		struct its_itte *itte;
>> +		/*
>> +		 * Clearing the mapping for that collection ID removes the
>> +		 * entry from the list. If there wasn't any before, we can
>> +		 * go home early.
>> +		 */
>> +		if (!collection)
>> +			goto out_unlock;
>> +
>> +		for_each_lpi(device, itte, kvm)
>> +			if (itte->collection &&
>> +			    itte->collection->collection_id == coll_id)
>> +				itte->collection = NULL;
>> +
>> +		list_del(&collection->coll_list);
>> +		kfree(collection);
>> +	} else {
>> +		if (!collection)
>> +			collection = new_coll;
>> +		else
>> +			kfree(new_coll);
>> +
>> +		vits_init_collection(kvm, collection, coll_id);
>> +		collection->target_addr = target_addr;
>> +	}
>> +
>> +out_unlock:
>> +	spin_unlock(&its->lock);
>> +	return 0;
>> +}
>> +
>> +/* The CLEAR command removes the pending state for a particular LPI. */
>> +static int vits_cmd_handle_clear(struct kvm *kvm, u64 *its_cmd)
>> +{
>> +	struct vgic_its *its = &kvm->arch.vgic.its;
>> +	u32 device_id;
>> +	u32 event_id;
>> +	struct its_itte *itte;
>> +	int ret = 0;
>> +
>> +	device_id = its_cmd_get_deviceid(its_cmd);
>> +	event_id = its_cmd_get_id(its_cmd);
>> +
>> +	spin_lock(&its->lock);
>> +
>> +	itte = find_itte(kvm, device_id, event_id);
>> +	if (!itte) {
>> +		ret = E_ITS_CLEAR_UNMAPPED_INTERRUPT;
>> +		goto out_unlock;
>> +	}
>> +
>> +	if (itte->collection)
>> +		__clear_bit(itte->collection->target_addr, itte->pending);
>> +
>> +out_unlock:
>> +	spin_unlock(&its->lock);
>> +	return ret;
>> +}
>> +
>> +/* The INV command syncs the pending bit from the memory tables. */
>> +static int vits_cmd_handle_inv(struct kvm *kvm, u64 *its_cmd)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +	u32 device_id;
>> +	u32 event_id;
>> +	struct its_itte *itte, *new_itte;
>> +	gpa_t propbase;
>> +	int ret;
>> +	u8 prop;
>> +
>> +	device_id = its_cmd_get_deviceid(its_cmd);
>> +	event_id = its_cmd_get_id(its_cmd);
>> +
>> +	spin_lock(&dist->its.lock);
>> +	itte = find_itte(kvm, device_id, event_id);
>> +	spin_unlock(&dist->its.lock);
>> +	if (!itte)
>> +		return E_ITS_INV_UNMAPPED_INTERRUPT;
>> +
>> +	/*
>> +	 * We cannot read from guest memory inside the spinlock, so we
>> +	 * need to re-read our tables to learn whether the LPI number we are
>> +	 * using is still valid.
>> +	 */
>> +	do {
>> +		propbase = BASER_BASE_ADDRESS(dist->propbaser);
>> +		ret = kvm_read_guest(kvm, propbase + itte->lpi - GIC_LPI_OFFSET,
>> +				     &prop, 1);
>> +		if (ret)
>> +			return ret;
>> +
>> +		spin_lock(&dist->its.lock);
>> +		new_itte = find_itte(kvm, device_id, event_id);
>> +		if (new_itte->lpi != itte->lpi) {
>> +			itte = new_itte;
>> +			spin_unlock(&dist->its.lock);
>> +			continue;
>> +		}
>> +		update_lpi_config(kvm, itte, prop);
> spec says the pending table should be sync'ed too. shouldn't we update
> the pending table in the guest address range?
>> +		spin_unlock(&dist->its.lock);
>> +	} while (0);
>> +	return 0;
>> +}
>> +
>> +/* The INVALL command requests flushing of all IRQ data in this collection. */
>> +static int vits_cmd_handle_invall(struct kvm *kvm, u64 *its_cmd)
>> +{
>> +	u32 coll_id = its_cmd_get_collection(its_cmd);
>> +	struct its_collection *collection;
>> +	struct kvm_vcpu *vcpu;
>> +
>> +	collection = find_collection(kvm, coll_id);
>> +	if (!collection)
>> +		return E_ITS_INVALL_UNMAPPED_COLLECTION;
>> +
>> +	vcpu = kvm_get_vcpu(kvm, collection->target_addr);
>> +
>> +	its_update_lpis_configuration(kvm);
>> +	its_sync_lpi_pending_table(vcpu);
> here we do?
>> +
>> +	return 0;
>> +}
>> +
>> +/* The MOVALL command moves all IRQs from one redistributor to another. */
>> +static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
>> +{
>> +	struct vgic_its *its = &kvm->arch.vgic.its;
>> +	u32 target1_addr = its_cmd_get_target_addr(its_cmd);
>> +	u32 target2_addr = its_cmd_mask_field(its_cmd, 3, 16, 32);
>> +	struct its_collection *collection;
>> +	struct its_device *device;
>> +	struct its_itte *itte;
>> +
>> +	if (target1_addr >= atomic_read(&kvm->online_vcpus) ||
>> +	    target2_addr >= atomic_read(&kvm->online_vcpus))
>> +		return E_ITS_MOVALL_PROCNUM_OOR;
>> +
>> +	if (target1_addr == target2_addr)
>> +		return 0;
>> +
>> +	spin_lock(&its->lock);
>> +	for_each_lpi(device, itte, kvm) {
>> +		/* remap all collections mapped to target address 1 */
>> +		collection = itte->collection;
>> +		if (collection && collection->target_addr == target1_addr)
>> +			collection->target_addr = target2_addr;
>> +
>> +		/* move pending state if LPI is affected */
>> +		if (test_and_clear_bit(target1_addr, itte->pending))
>> +			__set_bit(target2_addr, itte->pending);
>> +	}
>> +
>> +	spin_unlock(&its->lock);
>> +	return 0;
>> +}
>> +
>>  static int vits_handle_command(struct kvm_vcpu *vcpu, u64 *its_cmd)
>>  {
>> -	return -ENODEV;
>> +	u8 cmd = its_cmd_get_command(its_cmd);
>> +	int ret = -ENODEV;
>> +
>> +	switch (cmd) {
>> +	case GITS_CMD_MAPD:
>> +		ret = vits_cmd_handle_mapd(vcpu->kvm, its_cmd);
>> +		break;
>> +	case GITS_CMD_MAPC:
>> +		ret = vits_cmd_handle_mapc(vcpu->kvm, its_cmd);
>> +		break;
>> +	case GITS_CMD_MAPI:
>> +		ret = vits_cmd_handle_mapi(vcpu->kvm, its_cmd, cmd);
>> +		break;
>> +	case GITS_CMD_MAPTI:
>> +		ret = vits_cmd_handle_mapi(vcpu->kvm, its_cmd, cmd);
>> +		break;
>> +	case GITS_CMD_MOVI:
>> +		ret = vits_cmd_handle_movi(vcpu->kvm, its_cmd);
>> +		break;
>> +	case GITS_CMD_DISCARD:
>> +		ret = vits_cmd_handle_discard(vcpu->kvm, its_cmd);
>> +		break;
>> +	case GITS_CMD_CLEAR:
>> +		ret = vits_cmd_handle_clear(vcpu->kvm, its_cmd);
>> +		break;
>> +	case GITS_CMD_MOVALL:
>> +		ret = vits_cmd_handle_movall(vcpu->kvm, its_cmd);
>> +		break;
>> +	case GITS_CMD_INV:
>> +		ret = vits_cmd_handle_inv(vcpu->kvm, its_cmd);
>> +		break;
>> +	case GITS_CMD_INVALL:
>> +		ret = vits_cmd_handle_invall(vcpu->kvm, its_cmd);
>> +		break;
>> +	case GITS_CMD_SYNC:
>> +		/* we ignore this command: we are in sync all of the time */
>> +		ret = 0;
>> +		break;
>> +	}
>> +
>> +	return ret;
>>  }
>>  
>>  static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
>> @@ -554,6 +1048,7 @@ void vits_destroy(struct kvm *kvm)
>>  		list_for_each_safe(cur, temp, &dev->itt) {
>>  			itte = (container_of(cur, struct its_itte, itte_list));
>>  			list_del(cur);
>> +			kfree(itte->pending);
> should belong to a previous patch I think
> 
> Eric
>>  			kfree(itte);
>>  		}
>>  		list_del(dev_cur);
>> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
>> index cbc3877..830524a 100644
>> --- a/virt/kvm/arm/its-emul.h
>> +++ b/virt/kvm/arm/its-emul.h
>> @@ -39,4 +39,15 @@ void vits_destroy(struct kvm *kvm);
>>  bool vits_queue_lpis(struct kvm_vcpu *vcpu);
>>  void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int irq);
>>  
>> +#define E_ITS_MOVI_UNMAPPED_INTERRUPT		0x010107
>> +#define E_ITS_MOVI_UNMAPPED_COLLECTION		0x010109
>> +#define E_ITS_CLEAR_UNMAPPED_INTERRUPT		0x010507
>> +#define E_ITS_MAPC_PROCNUM_OOR			0x010902
>> +#define E_ITS_MAPTI_UNMAPPED_DEVICE		0x010a04
>> +#define E_ITS_MAPTI_PHYSICALID_OOR		0x010a06
>> +#define E_ITS_INV_UNMAPPED_INTERRUPT		0x010c07
>> +#define E_ITS_INVALL_UNMAPPED_COLLECTION	0x010d09
>> +#define E_ITS_MOVALL_PROCNUM_OOR		0x010e01
>> +#define E_ITS_DISCARD_UNMAPPED_INTERRUPT	0x010f07
>> +
>>  #endif
>>
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 11/15] KVM: arm64: handle pending bit for LPIs in ITS emulation
  2015-10-07  8:39   ` Pavel Fedin
@ 2015-10-07 19:53     ` Christoffer Dall
  0 siblings, 0 replies; 69+ messages in thread
From: Christoffer Dall @ 2015-10-07 19:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Oct 07, 2015 at 11:39:30AM +0300, Pavel Fedin wrote:
>  Hello!
> 
> > +/* Called with the distributor lock held by the caller. */
> > +void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi)
> > +{
> > +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> > +	struct its_itte *itte;
> > +
> > +	spin_lock(&its->lock);
> > +
> > +	/* Find the right ITTE and put the pending state back in there */
> > +	itte = find_itte_by_lpi(vcpu->kvm, lpi);
> > +	if (itte)
> > +		__set_bit(vcpu->vcpu_id, itte->pending);
> > +
> > +	spin_unlock(&its->lock);
> > +}
> 
>  I am working on implementing live migration for the ITS. And here i have one fundamental problem.
> vits_unqueue_lpi() processes only PENDING state. And looks like this corresponds to the HW
> implementation, which has only bitwise pending table. But, in terms of migration, we can actually
> have LPI in active state, while it's being processed.

I thought LPIs had strict fire-and-forget semantics, not allowing any
active state, and that they are either pending or inactive?


>  The question is - how can we handle it? Should we have one more bitwise table for active LPIs, or
> is it enough to remember only a single, currently active LPI? Can LPIs be preempted on a real
> hardware, or not?
> 
Perhaps you're asking if LPIs have active state semantics on real
hardware and thus supports threaded interrupt handling for LPIs?

That is not supported on real hardware, which I think addresses your
concerns.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 69+ messages in thread

end of thread, other threads:[~2015-10-07 19:53 UTC | newest]

Thread overview: 69+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-10 14:21 [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Andre Przywara
2015-07-10 14:21 ` [PATCH v2 01/15] KVM: arm/arm64: VGIC: don't track used LRs in the distributor Andre Przywara
2015-08-12  9:01   ` Eric Auger
2015-08-24 16:33     ` Andre Przywara
2015-08-31  8:42       ` Eric Auger
2015-09-02  9:00         ` Andre Przywara
2015-10-02  9:55   ` Pavel Fedin
2015-10-02 10:32     ` Andre Przywara
2015-10-02 10:39       ` Pavel Fedin
2015-10-02 12:39       ` Pavel Fedin
2015-10-02 12:49         ` Andre Przywara
2015-07-10 14:21 ` [PATCH v2 02/15] KVM: extend struct kvm_msi to hold a 32-bit device ID Andre Przywara
2015-07-10 14:21 ` [PATCH v2 03/15] KVM: arm/arm64: add emulation model specific destroy function Andre Przywara
2015-07-10 14:21 ` [PATCH v2 04/15] KVM: arm/arm64: extend arch CAP checks to allow per-VM capabilities Andre Przywara
2015-08-12 12:26   ` Eric Auger
2015-07-10 14:21 ` [PATCH v2 05/15] KVM: arm/arm64: make GIC frame address initialization model specific Andre Przywara
2015-08-12 13:02   ` Eric Auger
2015-08-24 17:24     ` Andre Przywara
2015-08-31  9:31       ` Eric Auger
2015-07-10 14:21 ` [PATCH v2 06/15] KVM: arm64: Introduce new MMIO region for the ITS base address Andre Przywara
2015-08-13 12:17   ` Eric Auger
2015-07-10 14:21 ` [PATCH v2 07/15] KVM: arm64: handle ITS related GICv3 redistributor registers Andre Przywara
2015-08-13 12:17   ` Eric Auger
2015-08-24 18:08     ` Andre Przywara
2015-07-10 14:21 ` [PATCH v2 08/15] KVM: arm64: introduce ITS emulation file with stub functions Andre Przywara
2015-08-13 12:48   ` Eric Auger
2015-08-25  9:39     ` Andre Przywara
2015-07-10 14:21 ` [PATCH v2 09/15] KVM: arm64: implement basic ITS register handlers Andre Przywara
2015-08-13 15:25   ` Eric Auger
2015-08-25 10:23     ` Andre Przywara
2015-10-02  7:51   ` Pavel Fedin
2015-07-10 14:21 ` [PATCH v2 10/15] KVM: arm64: add data structures to model ITS interrupt translation Andre Przywara
2015-08-13 15:46   ` Eric Auger
2015-08-25 11:15     ` Andre Przywara
2015-08-27 14:16       ` Eric Auger
2015-07-10 14:21 ` [PATCH v2 11/15] KVM: arm64: handle pending bit for LPIs in ITS emulation Andre Przywara
2015-08-14 11:58   ` Eric Auger
2015-08-25 14:34     ` Andre Przywara
2015-08-31  9:45       ` Eric Auger
2015-10-07  8:39   ` Pavel Fedin
2015-10-07 19:53     ` Christoffer Dall
2015-07-10 14:21 ` [PATCH v2 12/15] KVM: arm64: sync LPI configuration and pending tables Andre Przywara
2015-08-14 11:58   ` Eric Auger
2015-08-14 12:35     ` Eric Auger
2015-08-25 15:47       ` Andre Przywara
2015-08-31  9:51         ` Eric Auger
2015-08-25 15:27     ` Andre Przywara
2015-08-31  9:47       ` Eric Auger
2015-07-10 14:21 ` [PATCH v2 13/15] KVM: arm64: implement ITS command queue command handlers Andre Przywara
2015-08-17 13:33   ` Eric Auger
2015-10-07 14:54     ` Andre Przywara
2015-07-10 14:21 ` [PATCH v2 14/15] KVM: arm64: implement MSI injection in ITS emulation Andre Przywara
2015-07-31 13:22   ` Eric Auger
2015-08-02 20:20     ` Andre Przywara
2015-08-03  6:41       ` Pavel Fedin
2015-08-03  9:07         ` Eric Auger
2015-08-03  9:16           ` Pavel Fedin
2015-08-03 15:37             ` Eric Auger
2015-08-03 17:06               ` Marc Zyngier
2015-08-04  6:53                 ` Pavel Fedin
2015-08-24 14:14                 ` Andre Przywara
2015-08-17 13:44   ` Eric Auger
2015-07-10 14:21 ` [PATCH v2 15/15] KVM: arm64: enable ITS emulation as a virtual MSI controller Andre Przywara
2015-07-15  9:10   ` Pavel Fedin
2015-07-15  9:52     ` Andre Przywara
2015-07-15 10:01       ` Pavel Fedin
2015-07-15 12:02 ` [PATCH v2 00/15] KVM: arm64: GICv3 ITS emulation Pavel Fedin
2015-09-24 11:18 ` Pavel Fedin
2015-09-24 11:35   ` Andre Przywara

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).