All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
@ 2015-05-29  9:53 ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

The GICv3 ITS (Interrupt Translation Service) is a part of the
ARM GICv3 interrupt controller 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 gic-v3-emul.c.
Patch 01/13 gets rid of the internal tracking of the used LR for
an injected IRQ.
Patch 02/13 extends the KVM MSI ioctl to hold a device ID.
Patch 03/13 introduces an emulation model specific destroy function
to let the ITS be teared down correctly later.
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.1-rc5 and can be found at the its-emul/v1
branch of this repository [1].
For this to be used you need a GICv3 host machine, though it does not
rely on any host ITS bits (neither 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/v1
[2]: git://linux-arm.org/kvmtool.git
     http://www.linux-arm.org/git?p=kvmtool.git;a=log;h=refs/heads/its

Andre Przywara (13):
  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: 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 properties and status between guest and KVM
  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              |   10 +-
 Documentation/virtual/kvm/devices/arm-vgic.txt |    7 +
 arch/arm64/include/uapi/asm/kvm.h              |    3 +
 arch/arm64/kvm/Kconfig                         |    1 +
 arch/arm64/kvm/Makefile                        |    1 +
 include/kvm/arm_vgic.h                         |   39 +-
 include/linux/irqchip/arm-gic-v3.h             |   10 +
 include/uapi/linux/kvm.h                       |    4 +-
 virt/kvm/arm/its-emul.c                        | 1026 ++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h                        |   52 ++
 virt/kvm/arm/vgic-v2.c                         |    1 +
 virt/kvm/arm/vgic-v3-emul.c                    |   98 ++-
 virt/kvm/arm/vgic-v3.c                         |    1 +
 virt/kvm/arm/vgic.c                            |  280 ++++---
 virt/kvm/arm/vgic.h                            |    5 +
 15 files changed, 1426 insertions(+), 112 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] 104+ messages in thread

* [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
@ 2015-05-29  9:53 ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

The GICv3 ITS (Interrupt Translation Service) is a part of the
ARM GICv3 interrupt controller 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 gic-v3-emul.c.
Patch 01/13 gets rid of the internal tracking of the used LR for
an injected IRQ.
Patch 02/13 extends the KVM MSI ioctl to hold a device ID.
Patch 03/13 introduces an emulation model specific destroy function
to let the ITS be teared down correctly later.
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.1-rc5 and can be found at the its-emul/v1
branch of this repository [1].
For this to be used you need a GICv3 host machine, though it does not
rely on any host ITS bits (neither 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/v1
[2]: git://linux-arm.org/kvmtool.git
     http://www.linux-arm.org/git?p=kvmtool.git;a=log;h=refs/heads/its

Andre Przywara (13):
  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: 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 properties and status between guest and KVM
  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              |   10 +-
 Documentation/virtual/kvm/devices/arm-vgic.txt |    7 +
 arch/arm64/include/uapi/asm/kvm.h              |    3 +
 arch/arm64/kvm/Kconfig                         |    1 +
 arch/arm64/kvm/Makefile                        |    1 +
 include/kvm/arm_vgic.h                         |   39 +-
 include/linux/irqchip/arm-gic-v3.h             |   10 +
 include/uapi/linux/kvm.h                       |    4 +-
 virt/kvm/arm/its-emul.c                        | 1026 ++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h                        |   52 ++
 virt/kvm/arm/vgic-v2.c                         |    1 +
 virt/kvm/arm/vgic-v3-emul.c                    |   98 ++-
 virt/kvm/arm/vgic-v3.c                         |    1 +
 virt/kvm/arm/vgic.c                            |  280 ++++---
 virt/kvm/arm/vgic.h                            |    5 +
 15 files changed, 1426 insertions(+), 112 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] 104+ messages in thread

* [PATCH 01/13] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 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 78fb820..037b723 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -81,7 +81,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);
 
@@ -649,6 +648,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
@@ -660,9 +670,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);
 
 		/*
@@ -705,7 +717,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. */
@@ -1013,17 +1025,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);
@@ -1064,18 +1065,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
@@ -1087,23 +1076,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);
@@ -1128,9 +1126,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... */
@@ -1140,42 +1138,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);
@@ -1348,29 +1324,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);
 }
 
@@ -1592,11 +1583,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)
@@ -1607,18 +1596,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] 104+ messages in thread

* [PATCH 01/13] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

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 78fb820..037b723 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -81,7 +81,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);
 
@@ -649,6 +648,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
@@ -660,9 +670,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);
 
 		/*
@@ -705,7 +717,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. */
@@ -1013,17 +1025,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);
@@ -1064,18 +1065,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
@@ -1087,23 +1076,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);
@@ -1128,9 +1126,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... */
@@ -1140,42 +1138,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);
@@ -1348,29 +1324,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);
 }
 
@@ -1592,11 +1583,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)
@@ -1607,18 +1596,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] 104+ messages in thread

* [PATCH 02/13] KVM: extend struct kvm_msi to hold a 32-bit device ID
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 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.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 Documentation/virtual/kvm/api.txt | 8 ++++++--
 include/uapi/linux/kvm.h          | 4 +++-
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 9fa2bf8..891d64a 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2121,10 +2121,14 @@ 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 is valid, otherwise ignored.
+devid: If KVM_MSI_VALID_DEVID is set, contains a value to identify the device
+       that wrote the MSI message. For PCI, this is usually a BFD
+       identifier in the lower 16 bits.
 
 
 4.71 KVM_CREATE_PIT2
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 4b60056..2a23705 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -965,12 +965,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] 104+ messages in thread

* [PATCH 02/13] KVM: extend struct kvm_msi to hold a 32-bit device ID
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

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.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 Documentation/virtual/kvm/api.txt | 8 ++++++--
 include/uapi/linux/kvm.h          | 4 +++-
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 9fa2bf8..891d64a 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2121,10 +2121,14 @@ 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 is valid, otherwise ignored.
+devid: If KVM_MSI_VALID_DEVID is set, contains a value to identify the device
+       that wrote the MSI message. For PCI, this is usually a BFD
+       identifier in the lower 16 bits.
 
 
 4.71 KVM_CREATE_PIT2
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 4b60056..2a23705 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -965,12 +965,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] 104+ messages in thread

* [PATCH 03/13] KVM: arm/arm64: add emulation model specific destroy function
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

Currently we destroy the VGIC emulation in one function that cares for
all emulated models. The ITS emulation will require some
differentiation, so introduce a per-emulation-model destroy method.
Use it for a tiny GICv3 specific code already.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 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 e9c3a7a..fbfdd6f 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -818,6 +818,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)
 {
@@ -830,6 +838,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 037b723..6ea30e0 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -102,6 +102,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.
@@ -1631,6 +1639,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);
 
@@ -1647,7 +1657,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] 104+ messages in thread

* [PATCH 03/13] KVM: arm/arm64: add emulation model specific destroy function
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

Currently we destroy the VGIC emulation in one function that cares for
all emulated models. The ITS emulation will require some
differentiation, so introduce a per-emulation-model destroy method.
Use it for a tiny GICv3 specific code already.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 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 e9c3a7a..fbfdd6f 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -818,6 +818,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)
 {
@@ -830,6 +838,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 037b723..6ea30e0 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -102,6 +102,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.
@@ -1631,6 +1639,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);
 
@@ -1647,7 +1657,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] 104+ messages in thread

* [PATCH 04/13] KVM: arm64: Introduce new MMIO region for the ITS base address
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 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 |  7 +++++++
 arch/arm64/include/uapi/asm/kvm.h              |  3 +++
 include/kvm/arm_vgic.h                         |  3 +++
 virt/kvm/arm/vgic-v3-emul.c                    |  1 +
 virt/kvm/arm/vgic.c                            | 17 +++++++++++++++++
 virt/kvm/arm/vgic.h                            |  1 +
 6 files changed, 32 insertions(+)

diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
index 3fb9054..1f89001 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic.txt
@@ -39,6 +39,13 @@ 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
+      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.
+      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..e42435c 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -82,8 +82,11 @@ struct kvm_regs {
 #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..37725bb 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 for the MSI control block (V2M/ITS) */
+	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 fbfdd6f..16c6d8a 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -1012,6 +1012,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 6ea30e0..2e9723aa 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -932,6 +932,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;
@@ -1835,6 +1845,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 	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;
+	kvm->arch.vgic.vgic_its_base = VGIC_ADDR_UNDEF;
 
 out_unlock:
 	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
@@ -1932,6 +1943,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] 104+ messages in thread

* [PATCH 04/13] KVM: arm64: Introduce new MMIO region for the ITS base address
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

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 |  7 +++++++
 arch/arm64/include/uapi/asm/kvm.h              |  3 +++
 include/kvm/arm_vgic.h                         |  3 +++
 virt/kvm/arm/vgic-v3-emul.c                    |  1 +
 virt/kvm/arm/vgic.c                            | 17 +++++++++++++++++
 virt/kvm/arm/vgic.h                            |  1 +
 6 files changed, 32 insertions(+)

diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
index 3fb9054..1f89001 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic.txt
@@ -39,6 +39,13 @@ 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
+      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.
+      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..e42435c 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -82,8 +82,11 @@ struct kvm_regs {
 #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..37725bb 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 for the MSI control block (V2M/ITS) */
+	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 fbfdd6f..16c6d8a 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -1012,6 +1012,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 6ea30e0..2e9723aa 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -932,6 +932,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;
@@ -1835,6 +1845,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 	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;
+	kvm->arch.vgic.vgic_its_base = VGIC_ADDR_UNDEF;
 
 out_unlock:
 	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
@@ -1932,6 +1943,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] 104+ messages in thread

* [PATCH 05/13] KVM: arm64: handle ITS related GICv3 redistributor registers
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 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      |  4 ++++
 virt/kvm/arm/vgic-v3-emul.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic.c         | 35 +++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic.h         |  4 ++++
 4 files changed, 86 insertions(+)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 37725bb..9ea0b3b 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -256,6 +256,10 @@ struct vgic_dist {
 	struct vgic_vm_ops	vm_ops;
 	struct vgic_io_device	dist_iodev;
 	struct vgic_io_device	*redist_iodevs;
+
+	u64			propbaser;
+	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 16c6d8a..04f3aed 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -607,6 +607,37 @@ 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;
+
+	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[] = {
@@ -635,6 +666,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 2e9723aa..0a9236d 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -448,6 +448,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] 104+ messages in thread

* [PATCH 05/13] KVM: arm64: handle ITS related GICv3 redistributor registers
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

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      |  4 ++++
 virt/kvm/arm/vgic-v3-emul.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic.c         | 35 +++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic.h         |  4 ++++
 4 files changed, 86 insertions(+)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 37725bb..9ea0b3b 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -256,6 +256,10 @@ struct vgic_dist {
 	struct vgic_vm_ops	vm_ops;
 	struct vgic_io_device	dist_iodev;
 	struct vgic_io_device	*redist_iodevs;
+
+	u64			propbaser;
+	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 16c6d8a..04f3aed 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -607,6 +607,37 @@ 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;
+
+	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[] = {
@@ -635,6 +666,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 2e9723aa..0a9236d 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -448,6 +448,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] 104+ messages in thread

* [PATCH 06/13] KVM: arm64: introduce ITS emulation file with stub functions
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 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 skeletton 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            | 127 +++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h            |  35 ++++++++++
 virt/kvm/arm/vgic-v3-emul.c        |  22 ++++++-
 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 d5904f8..0d09189 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 9ea0b3b..d76c2d9 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;
@@ -260,6 +265,7 @@ struct vgic_dist {
 	u64			propbaser;
 	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..7b283ce
--- /dev/null
+++ b/virt/kvm/arm/its-emul.c
@@ -0,0 +1,127 @@
+/*
+ * 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,
+	},
+};
+
+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;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
+		return -ENXIO;
+
+	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 04f3aed..4e40684 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)
@@ -506,9 +507,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;
 }
 
@@ -816,6 +828,10 @@ static int vgic_v3_map_resources(struct kvm *kvm,
 		rdbase += GIC_V3_REDIST_SIZE;
 	}
 
+	ret = vits_init(kvm);
+	if (ret && ret != -ENXIO)
+		goto out_unregister;
+
 	dist->redist_iodevs = iodevs;
 	dist->ready = true;
 	goto out;
-- 
2.3.5

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

* [PATCH 06/13] KVM: arm64: introduce ITS emulation file with stub functions
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

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 skeletton 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            | 127 +++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h            |  35 ++++++++++
 virt/kvm/arm/vgic-v3-emul.c        |  22 ++++++-
 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 d5904f8..0d09189 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 9ea0b3b..d76c2d9 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;
@@ -260,6 +265,7 @@ struct vgic_dist {
 	u64			propbaser;
 	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..7b283ce
--- /dev/null
+++ b/virt/kvm/arm/its-emul.c
@@ -0,0 +1,127 @@
+/*
+ * 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,
+	},
+};
+
+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;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
+		return -ENXIO;
+
+	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 04f3aed..4e40684 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)
@@ -506,9 +507,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;
 }
 
@@ -816,6 +828,10 @@ static int vgic_v3_map_resources(struct kvm *kvm,
 		rdbase += GIC_V3_REDIST_SIZE;
 	}
 
+	ret = vits_init(kvm);
+	if (ret && ret != -ENXIO)
+		goto out_unregister;
+
 	dist->redist_iodevs = iodevs;
 	dist->ready = true;
 	goto out;
-- 
2.3.5

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

* [PATCH 07/13] KVM: arm64: implement basic ITS register handlers
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 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,CREAD,CWRITER}
  those implement the ITS command buffer handling

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            | 172 +++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h            |   1 +
 virt/kvm/arm/vgic-v3-emul.c        |   2 +
 5 files changed, 186 insertions(+)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index d76c2d9..3b8e3a1 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 7b283ce..82bc34a 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)
+
+/* distributor lock is hold 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,107 @@ 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);
+	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);
+}
+
 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;
+	u64 cmd_buf[4];
+	gpa_t cbaser = its_cmd_buffer_base(vcpu->kvm);
+	u32 reg;
+	int ret;
+
+	spin_lock(&its->lock);
+	switch (offset & ~3) {
+	case 0x00:
+		reg = its->cwriter & 0xfffe0;
+		vgic_reg_access(mmio, &reg, offset & 3,
+				ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
+		reg &= 0xfffe0;
+		if (reg > its_cmd_buffer_size(vcpu->kvm))
+			break;
+		while (its->creadr != reg) {
+			ret = kvm_read_guest(vcpu->kvm, cbaser + its->creadr,
+					     cmd_buf, 32);
+			if (ret)
+				break;
+			vits_handle_command(vcpu, cmd_buf);
+			its->creadr += 32;
+			if (its->creadr == its_cmd_buffer_size(vcpu->kvm))
+				its->creadr = 0;
+		}
+		its->cwriter = reg;
+		break;
+	case 0x04:
+		vgic_reg_access(mmio, &reg, offset & 3,
+				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
+		break;
+	}
+	spin_unlock(&its->lock);
 	return false;
 }
 
@@ -64,6 +203,22 @@ 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;
+
+	spin_lock(&its->lock);
+	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;
+	}
+	spin_unlock(&its->lock);
 	return false;
 }
 
@@ -119,9 +274,26 @@ int vits_init(struct kvm *kvm)
 	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
 		return -ENXIO;
 
+	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 4e40684..fa81c4b 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -881,6 +881,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] 104+ messages in thread

* [PATCH 07/13] KVM: arm64: implement basic ITS register handlers
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

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

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            | 172 +++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h            |   1 +
 virt/kvm/arm/vgic-v3-emul.c        |   2 +
 5 files changed, 186 insertions(+)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index d76c2d9..3b8e3a1 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 7b283ce..82bc34a 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)
+
+/* distributor lock is hold 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,107 @@ 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);
+	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);
+}
+
 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;
+	u64 cmd_buf[4];
+	gpa_t cbaser = its_cmd_buffer_base(vcpu->kvm);
+	u32 reg;
+	int ret;
+
+	spin_lock(&its->lock);
+	switch (offset & ~3) {
+	case 0x00:
+		reg = its->cwriter & 0xfffe0;
+		vgic_reg_access(mmio, &reg, offset & 3,
+				ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
+		reg &= 0xfffe0;
+		if (reg > its_cmd_buffer_size(vcpu->kvm))
+			break;
+		while (its->creadr != reg) {
+			ret = kvm_read_guest(vcpu->kvm, cbaser + its->creadr,
+					     cmd_buf, 32);
+			if (ret)
+				break;
+			vits_handle_command(vcpu, cmd_buf);
+			its->creadr += 32;
+			if (its->creadr == its_cmd_buffer_size(vcpu->kvm))
+				its->creadr = 0;
+		}
+		its->cwriter = reg;
+		break;
+	case 0x04:
+		vgic_reg_access(mmio, &reg, offset & 3,
+				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
+		break;
+	}
+	spin_unlock(&its->lock);
 	return false;
 }
 
@@ -64,6 +203,22 @@ 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;
+
+	spin_lock(&its->lock);
+	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;
+	}
+	spin_unlock(&its->lock);
 	return false;
 }
 
@@ -119,9 +274,26 @@ int vits_init(struct kvm *kvm)
 	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
 		return -ENXIO;
 
+	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 4e40684..fa81c4b 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -881,6 +881,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] 104+ messages in thread

* [PATCH 08/13] KVM: arm64: add data structures to model ITS interrupt translation
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 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
the lists becomes painful, 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 | 45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 3b8e3a1..fa17df6 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 82bc34a..f0f4a9c 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)
 
 /* distributor lock is hold by the VGIC MMIO handler */
@@ -280,6 +300,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;
@@ -289,11 +312,33 @@ 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;
 
+	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] 104+ messages in thread

* [PATCH 08/13] KVM: arm64: add data structures to model ITS interrupt translation
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

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
the lists becomes painful, 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 | 45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 3b8e3a1..fa17df6 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 82bc34a..f0f4a9c 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)
 
 /* distributor lock is hold by the VGIC MMIO handler */
@@ -280,6 +300,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;
@@ -289,11 +312,33 @@ 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;
 
+	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] 104+ messages in thread

* [PATCH 09/13] KVM: arm64: handle pending bit for LPIs in ITS emulation
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 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     | 66 +++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h     |  3 ++
 virt/kvm/arm/vgic-v3-emul.c |  2 ++
 virt/kvm/arm/vgic.c         | 68 +++++++++++++++++++++++++++++++++------------
 5 files changed, 124 insertions(+), 17 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index fa17df6..de19c34 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 f0f4a9c..f75fb9e 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)
 
 /* distributor lock is hold by the VGIC MMIO handler */
@@ -145,6 +163,54 @@ 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;
+
+	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;
+}
+
+/* is 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 fa81c4b..66640c2fa 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -901,6 +901,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;
 
 	kvm->arch.max_vcpus = KVM_MAX_VCPUS;
 }
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 0a9236d..9f7b05f 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -97,6 +97,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);
@@ -1149,25 +1163,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);
 }
@@ -1179,7 +1201,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;
@@ -1187,7 +1208,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);
 
@@ -1267,8 +1287,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) {
@@ -1389,6 +1413,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;
 
@@ -1413,7 +1447,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] 104+ messages in thread

* [PATCH 09/13] KVM: arm64: handle pending bit for LPIs in ITS emulation
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

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     | 66 +++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/its-emul.h     |  3 ++
 virt/kvm/arm/vgic-v3-emul.c |  2 ++
 virt/kvm/arm/vgic.c         | 68 +++++++++++++++++++++++++++++++++------------
 5 files changed, 124 insertions(+), 17 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index fa17df6..de19c34 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 f0f4a9c..f75fb9e 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)
 
 /* distributor lock is hold by the VGIC MMIO handler */
@@ -145,6 +163,54 @@ 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;
+
+	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;
+}
+
+/* is 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 fa81c4b..66640c2fa 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -901,6 +901,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;
 
 	kvm->arch.max_vcpus = KVM_MAX_VCPUS;
 }
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 0a9236d..9f7b05f 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -97,6 +97,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);
@@ -1149,25 +1163,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);
 }
@@ -1179,7 +1201,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;
@@ -1187,7 +1208,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);
 
@@ -1267,8 +1287,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) {
@@ -1389,6 +1413,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;
 
@@ -1413,7 +1447,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] 104+ messages in thread

* [PATCH 10/13] KVM: arm64: sync LPI properties and status between guest and KVM
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

The properties and status of the GICv3 LPIs are hold 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 property and status table in the kernel.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/its-emul.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 140 insertions(+)

diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index f75fb9e..afd440e 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,7 +71,140 @@ 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_property(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)
+#define PROPBASE_TSIZE(x) (1U << (x & 0x1f))
+
+/*
+ * Scan the whole LPI property table and put the LPI configuration
+ * data in our own data structures. This relies on the LPI being
+ * mapped before.
+ * We scan from two sides:
+ * 1) for each byte in the table we care for the ones being enabled
+ * 2) for each mapped LPI we look into the table to spot LPIs being disabled
+ * Must be called with the ITS lock held.
+ */
+static bool its_update_lpi_properties(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	u8 *prop;
+	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 = PROPBASE_TSIZE(dist->propbaser);
+
+	prop = kmalloc(CHUNK_SIZE, GFP_KERNEL);
+	if (!prop)
+		return false;
+
+	while (tsize > 0) {
+		int chunksize = min(tsize, CHUNK_SIZE);
+
+		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
+		if (ret) {
+			kfree(prop);
+			break;
+		}
+
+		/*
+		 * 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) {
+			/*
+			 * Is the LPI covered by that part of the table we
+			 * are currently looking at?
+			 */
+			if (itte->lpi < lpi)
+				continue;
+			if (itte->lpi >= lpi + chunksize)
+				continue;
+
+			update_lpi_property(kvm, itte,
+					    prop[itte->lpi - lpi]);
+		}
+		tsize -= chunksize;
+		lpi += chunksize;
+		propbase += chunksize;
+	}
+
+	kfree(prop);
+	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.
+ * Must be called with the ITS lock held.
+ */
+static bool its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
+{
+	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+	unsigned long *pendmask;
+	u32 nr_lpis;
+	gpa_t pendbase;
+	int lpi = GIC_LPI_OFFSET;
+	struct its_itte *itte;
+	struct its_device *device;
+	int ret;
+	int lpi_bit, nr_bits;
+
+	pendbase = BASER_BASE_ADDRESS(dist->pendbaser[vcpu->vcpu_id]);
+	nr_lpis = GIC_LPI_OFFSET;
+
+	pendmask = kmalloc(CHUNK_SIZE, GFP_KERNEL);
+	if (!pendmask)
+		return false;
+
+	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)
+			break;
+
+		for_each_lpi(device, itte, vcpu->kvm) {
+			lpi_bit = itte->lpi - lpi;
+			if (lpi_bit < 0)
+				continue;
+			if (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);
+		}
+		nr_lpis -= nr_bits;
+		lpi += nr_bits;
+		pendbase += nr_bits / 8;
+	}
+
+	kfree(pendmask);
+	return true;
+}
 
 /* distributor lock is hold by the VGIC MMIO handler */
 static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
@@ -350,6 +484,12 @@ static const struct vgic_io_range vgicv3_its_ranges[] = {
 
 void vgic_enable_lpis(struct kvm_vcpu *vcpu)
 {
+	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
+
+	spin_lock(&its->lock);
+	its_update_lpi_properties(vcpu->kvm);
+	its_sync_lpi_pending_table(vcpu);
+	spin_unlock(&its->lock);
 }
 
 int vits_init(struct kvm *kvm)
-- 
2.3.5

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

* [PATCH 10/13] KVM: arm64: sync LPI properties and status between guest and KVM
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

The properties and status of the GICv3 LPIs are hold 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 property and status table in the kernel.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/its-emul.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 140 insertions(+)

diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index f75fb9e..afd440e 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,7 +71,140 @@ 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_property(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)
+#define PROPBASE_TSIZE(x) (1U << (x & 0x1f))
+
+/*
+ * Scan the whole LPI property table and put the LPI configuration
+ * data in our own data structures. This relies on the LPI being
+ * mapped before.
+ * We scan from two sides:
+ * 1) for each byte in the table we care for the ones being enabled
+ * 2) for each mapped LPI we look into the table to spot LPIs being disabled
+ * Must be called with the ITS lock held.
+ */
+static bool its_update_lpi_properties(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	u8 *prop;
+	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 = PROPBASE_TSIZE(dist->propbaser);
+
+	prop = kmalloc(CHUNK_SIZE, GFP_KERNEL);
+	if (!prop)
+		return false;
+
+	while (tsize > 0) {
+		int chunksize = min(tsize, CHUNK_SIZE);
+
+		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
+		if (ret) {
+			kfree(prop);
+			break;
+		}
+
+		/*
+		 * 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) {
+			/*
+			 * Is the LPI covered by that part of the table we
+			 * are currently looking at?
+			 */
+			if (itte->lpi < lpi)
+				continue;
+			if (itte->lpi >= lpi + chunksize)
+				continue;
+
+			update_lpi_property(kvm, itte,
+					    prop[itte->lpi - lpi]);
+		}
+		tsize -= chunksize;
+		lpi += chunksize;
+		propbase += chunksize;
+	}
+
+	kfree(prop);
+	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.
+ * Must be called with the ITS lock held.
+ */
+static bool its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
+{
+	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+	unsigned long *pendmask;
+	u32 nr_lpis;
+	gpa_t pendbase;
+	int lpi = GIC_LPI_OFFSET;
+	struct its_itte *itte;
+	struct its_device *device;
+	int ret;
+	int lpi_bit, nr_bits;
+
+	pendbase = BASER_BASE_ADDRESS(dist->pendbaser[vcpu->vcpu_id]);
+	nr_lpis = GIC_LPI_OFFSET;
+
+	pendmask = kmalloc(CHUNK_SIZE, GFP_KERNEL);
+	if (!pendmask)
+		return false;
+
+	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)
+			break;
+
+		for_each_lpi(device, itte, vcpu->kvm) {
+			lpi_bit = itte->lpi - lpi;
+			if (lpi_bit < 0)
+				continue;
+			if (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);
+		}
+		nr_lpis -= nr_bits;
+		lpi += nr_bits;
+		pendbase += nr_bits / 8;
+	}
+
+	kfree(pendmask);
+	return true;
+}
 
 /* distributor lock is hold by the VGIC MMIO handler */
 static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
@@ -350,6 +484,12 @@ static const struct vgic_io_range vgicv3_its_ranges[] = {
 
 void vgic_enable_lpis(struct kvm_vcpu *vcpu)
 {
+	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
+
+	spin_lock(&its->lock);
+	its_update_lpi_properties(vcpu->kvm);
+	its_sync_lpi_pending_table(vcpu);
+	spin_unlock(&its->lock);
 }
 
 int vits_init(struct kvm *kvm)
-- 
2.3.5

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

* [PATCH 11/13] KVM: arm64: implement ITS command queue command handlers
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 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 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.
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).

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

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 0b450c7..651aacc 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -254,6 +254,7 @@
 #define GITS_CMD_MAPD			0x08
 #define GITS_CMD_MAPC			0x09
 #define GITS_CMD_MAPVI			0x0a
+#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 afd440e..574cf05 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)
 
@@ -345,9 +387,386 @@ 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)
+
+/*
+ * Handles the DISCARD command, which frees an ITTE.
+ * Must be called with the ITS lock held.
+ */
+static int vits_cmd_handle_discard(struct kvm *kvm, u64 *its_cmd)
+{
+	u32 device_id;
+	u32 event_id;
+	struct its_itte *itte;
+
+	device_id = its_cmd_get_deviceid(its_cmd);
+	event_id = its_cmd_get_id(its_cmd);
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte || !itte->collection)
+		return E_ITS_DISCARD_UNMAPPED_INTERRUPT;
+
+	clear_bit(itte->collection->target_addr, itte->pending);
+
+	list_del(&itte->itte_list);
+	kfree(itte);
+	return 0;
+}
+
+/*
+ * Handles the MOVI command, which moves an ITTE to a different collection.
+ * Must be called with the ITS lock held.
+ */
+static int vits_cmd_handle_movi(struct kvm *kvm, u64 *its_cmd)
+{
+	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;
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte)
+		return E_ITS_MOVI_UNMAPPED_INTERRUPT;
+	if (!itte->collection)
+		return E_ITS_MOVI_UNMAPPED_COLLECTION;
+
+	collection = find_collection(kvm, coll_id);
+	if (!collection)
+		return E_ITS_MOVI_UNMAPPED_COLLECTION;
+
+	if (test_and_clear_bit(itte->collection->target_addr, itte->pending))
+		set_bit(collection->target_addr, itte->pending);
+
+	itte->collection = collection;
+
+	return 0;
+}
+
+static struct its_collection *vits_new_collection(struct kvm *kvm, u32 coll_id)
+{
+	struct its_collection *collection;
+
+	collection = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
+	if (!collection)
+		return NULL;
+	collection->collection_id = coll_id;
+
+	list_add_tail(&collection->coll_list,
+		&kvm->arch.vgic.its.collection_list);
+
+	return collection;
+}
+
+/*
+ * Handles the MAPVI and MAPI command, which maps LPIs to ITTEs.
+ * Must be called with the ITS lock held.
+ */
+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;
+	struct its_device *device;
+	struct its_collection *collection, *new_coll = NULL;
+	int lpi_nr;
+
+	device = find_its_device(kvm, device_id);
+	if (!device)
+		return E_ITS_MAPVI_UNMAPPED_DEVICE;
+
+	collection = find_collection(kvm, coll_id);
+	if (!collection) {
+		new_coll = vits_new_collection(kvm, coll_id);
+		if (!new_coll)
+			return -ENOMEM;
+	}
+
+	if (cmd == GITS_CMD_MAPVI)
+		lpi_nr = its_cmd_get_physical_id(its_cmd);
+	else
+		lpi_nr = event_id;
+	if (lpi_nr < GIC_LPI_OFFSET ||
+	    lpi_nr >= PROPBASE_TSIZE(dist->propbaser))
+		return E_ITS_MAPVI_PHYSICALID_OOR;
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte) {
+		/* Allocate a new ITTE */
+		itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
+		if (!itte) {
+			kfree(new_coll);
+			return -ENOMEM;
+		}
+		itte->pending = kcalloc(BITS_TO_LONGS(dist->nr_cpus),
+					sizeof(long), GFP_KERNEL);
+		if (!itte->pending) {
+			kfree(itte);
+			kfree(new_coll);
+			return -ENOMEM;
+		}
+
+		itte->event_id	= event_id;
+
+		list_add_tail(&itte->itte_list, &device->itt);
+	}
+
+	itte->collection = collection ? collection : new_coll;
+	itte->lpi = lpi_nr;
+
+	return 0;
+}
+
+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);
+}
+
+/* Must be called with the ITS lock held. */
+static int vits_cmd_handle_mapd(struct kvm *kvm, u64 *its_cmd)
+{
+	bool valid = its_cmd_get_validbit(its_cmd);
+	u32 device_id = its_cmd_get_deviceid(its_cmd);
+	struct its_device *device;
+
+	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)
+		return 0;
+
+	device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
+	if (!device)
+		return -ENOMEM;
+
+	device->device_id = device_id;
+	INIT_LIST_HEAD(&device->itt);
+
+	list_add_tail(&device->dev_list,
+		      &kvm->arch.vgic.its.device_list);
+
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
+static int vits_cmd_handle_mapc(struct kvm *kvm, u64 *its_cmd)
+{
+	u16 coll_id;
+	u32 target_addr;
+	struct its_collection *collection;
+	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;
+
+	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)
+			return 0;
+
+		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);
+		return 0;
+	}
+
+	if (!collection) {
+		collection = vits_new_collection(kvm, coll_id);
+		if (!collection)
+			return -ENOMEM;
+	}
+
+	collection->target_addr = target_addr;
+
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
+static int vits_cmd_handle_clear(struct kvm *kvm, u64 *its_cmd)
+{
+	u32 device_id;
+	u32 event_id;
+	struct its_itte *itte;
+
+	device_id = its_cmd_get_deviceid(its_cmd);
+	event_id = its_cmd_get_id(its_cmd);
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte)
+		return E_ITS_CLEAR_UNMAPPED_INTERRUPT;
+
+	if (itte->collection)
+		clear_bit(itte->collection->target_addr, itte->pending);
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
+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;
+	gpa_t propbase;
+	int ret;
+	u8 prop;
+
+	device_id = its_cmd_get_deviceid(its_cmd);
+	event_id = its_cmd_get_id(its_cmd);
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte)
+		return E_ITS_INV_UNMAPPED_INTERRUPT;
+
+	propbase = BASER_BASE_ADDRESS(dist->propbaser);
+	ret = kvm_read_guest(kvm, propbase + itte->lpi - GIC_LPI_OFFSET,
+			     &prop, 1);
+	if (ret)
+		return ret;
+
+	update_lpi_property(kvm, itte, prop);
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
+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_lpi_properties(kvm);
+	its_sync_lpi_pending_table(vcpu);
+
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
+static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
+{
+	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;
+
+	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);
+	}
+
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
 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_MAPVI:
+		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 those commands: we are in sync all of the time */
+		break;
+	}
+
+	return ret;
 }
 
 static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
@@ -532,6 +951,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 cc5d5ff..6152d04 100644
--- a/virt/kvm/arm/its-emul.h
+++ b/virt/kvm/arm/its-emul.h
@@ -36,4 +36,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_MAPVI_UNMAPPED_DEVICE		0x010a04
+#define E_ITS_MAPVI_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] 104+ messages in thread

* [PATCH 11/13] KVM: arm64: implement ITS command queue command handlers
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

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 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.
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).

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

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 0b450c7..651aacc 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -254,6 +254,7 @@
 #define GITS_CMD_MAPD			0x08
 #define GITS_CMD_MAPC			0x09
 #define GITS_CMD_MAPVI			0x0a
+#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 afd440e..574cf05 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)
 
@@ -345,9 +387,386 @@ 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)
+
+/*
+ * Handles the DISCARD command, which frees an ITTE.
+ * Must be called with the ITS lock held.
+ */
+static int vits_cmd_handle_discard(struct kvm *kvm, u64 *its_cmd)
+{
+	u32 device_id;
+	u32 event_id;
+	struct its_itte *itte;
+
+	device_id = its_cmd_get_deviceid(its_cmd);
+	event_id = its_cmd_get_id(its_cmd);
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte || !itte->collection)
+		return E_ITS_DISCARD_UNMAPPED_INTERRUPT;
+
+	clear_bit(itte->collection->target_addr, itte->pending);
+
+	list_del(&itte->itte_list);
+	kfree(itte);
+	return 0;
+}
+
+/*
+ * Handles the MOVI command, which moves an ITTE to a different collection.
+ * Must be called with the ITS lock held.
+ */
+static int vits_cmd_handle_movi(struct kvm *kvm, u64 *its_cmd)
+{
+	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;
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte)
+		return E_ITS_MOVI_UNMAPPED_INTERRUPT;
+	if (!itte->collection)
+		return E_ITS_MOVI_UNMAPPED_COLLECTION;
+
+	collection = find_collection(kvm, coll_id);
+	if (!collection)
+		return E_ITS_MOVI_UNMAPPED_COLLECTION;
+
+	if (test_and_clear_bit(itte->collection->target_addr, itte->pending))
+		set_bit(collection->target_addr, itte->pending);
+
+	itte->collection = collection;
+
+	return 0;
+}
+
+static struct its_collection *vits_new_collection(struct kvm *kvm, u32 coll_id)
+{
+	struct its_collection *collection;
+
+	collection = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
+	if (!collection)
+		return NULL;
+	collection->collection_id = coll_id;
+
+	list_add_tail(&collection->coll_list,
+		&kvm->arch.vgic.its.collection_list);
+
+	return collection;
+}
+
+/*
+ * Handles the MAPVI and MAPI command, which maps LPIs to ITTEs.
+ * Must be called with the ITS lock held.
+ */
+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;
+	struct its_device *device;
+	struct its_collection *collection, *new_coll = NULL;
+	int lpi_nr;
+
+	device = find_its_device(kvm, device_id);
+	if (!device)
+		return E_ITS_MAPVI_UNMAPPED_DEVICE;
+
+	collection = find_collection(kvm, coll_id);
+	if (!collection) {
+		new_coll = vits_new_collection(kvm, coll_id);
+		if (!new_coll)
+			return -ENOMEM;
+	}
+
+	if (cmd == GITS_CMD_MAPVI)
+		lpi_nr = its_cmd_get_physical_id(its_cmd);
+	else
+		lpi_nr = event_id;
+	if (lpi_nr < GIC_LPI_OFFSET ||
+	    lpi_nr >= PROPBASE_TSIZE(dist->propbaser))
+		return E_ITS_MAPVI_PHYSICALID_OOR;
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte) {
+		/* Allocate a new ITTE */
+		itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
+		if (!itte) {
+			kfree(new_coll);
+			return -ENOMEM;
+		}
+		itte->pending = kcalloc(BITS_TO_LONGS(dist->nr_cpus),
+					sizeof(long), GFP_KERNEL);
+		if (!itte->pending) {
+			kfree(itte);
+			kfree(new_coll);
+			return -ENOMEM;
+		}
+
+		itte->event_id	= event_id;
+
+		list_add_tail(&itte->itte_list, &device->itt);
+	}
+
+	itte->collection = collection ? collection : new_coll;
+	itte->lpi = lpi_nr;
+
+	return 0;
+}
+
+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);
+}
+
+/* Must be called with the ITS lock held. */
+static int vits_cmd_handle_mapd(struct kvm *kvm, u64 *its_cmd)
+{
+	bool valid = its_cmd_get_validbit(its_cmd);
+	u32 device_id = its_cmd_get_deviceid(its_cmd);
+	struct its_device *device;
+
+	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)
+		return 0;
+
+	device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
+	if (!device)
+		return -ENOMEM;
+
+	device->device_id = device_id;
+	INIT_LIST_HEAD(&device->itt);
+
+	list_add_tail(&device->dev_list,
+		      &kvm->arch.vgic.its.device_list);
+
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
+static int vits_cmd_handle_mapc(struct kvm *kvm, u64 *its_cmd)
+{
+	u16 coll_id;
+	u32 target_addr;
+	struct its_collection *collection;
+	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;
+
+	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)
+			return 0;
+
+		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);
+		return 0;
+	}
+
+	if (!collection) {
+		collection = vits_new_collection(kvm, coll_id);
+		if (!collection)
+			return -ENOMEM;
+	}
+
+	collection->target_addr = target_addr;
+
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
+static int vits_cmd_handle_clear(struct kvm *kvm, u64 *its_cmd)
+{
+	u32 device_id;
+	u32 event_id;
+	struct its_itte *itte;
+
+	device_id = its_cmd_get_deviceid(its_cmd);
+	event_id = its_cmd_get_id(its_cmd);
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte)
+		return E_ITS_CLEAR_UNMAPPED_INTERRUPT;
+
+	if (itte->collection)
+		clear_bit(itte->collection->target_addr, itte->pending);
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
+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;
+	gpa_t propbase;
+	int ret;
+	u8 prop;
+
+	device_id = its_cmd_get_deviceid(its_cmd);
+	event_id = its_cmd_get_id(its_cmd);
+
+	itte = find_itte(kvm, device_id, event_id);
+	if (!itte)
+		return E_ITS_INV_UNMAPPED_INTERRUPT;
+
+	propbase = BASER_BASE_ADDRESS(dist->propbaser);
+	ret = kvm_read_guest(kvm, propbase + itte->lpi - GIC_LPI_OFFSET,
+			     &prop, 1);
+	if (ret)
+		return ret;
+
+	update_lpi_property(kvm, itte, prop);
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
+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_lpi_properties(kvm);
+	its_sync_lpi_pending_table(vcpu);
+
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
+static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
+{
+	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;
+
+	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);
+	}
+
+	return 0;
+}
+
+/* Must be called with the ITS lock held. */
 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_MAPVI:
+		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 those commands: we are in sync all of the time */
+		break;
+	}
+
+	return ret;
 }
 
 static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
@@ -532,6 +951,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 cc5d5ff..6152d04 100644
--- a/virt/kvm/arm/its-emul.h
+++ b/virt/kvm/arm/its-emul.h
@@ -36,4 +36,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_MAPVI_UNMAPPED_DEVICE		0x010a04
+#define E_ITS_MAPVI_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] 104+ messages in thread

* [PATCH 12/13] KVM: arm64: implement MSI injection in ITS emulation
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 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 receivce
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).

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

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index de19c34..6bb138d 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 574cf05..35e886c 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -340,6 +340,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.
diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
index 6152d04..cac1406 100644
--- a/virt/kvm/arm/its-emul.h
+++ b/virt/kvm/arm/its-emul.h
@@ -33,6 +33,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 66640c2fa..4513551 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -901,6 +901,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] 104+ messages in thread

* [PATCH 12/13] KVM: arm64: implement MSI injection in ITS emulation
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

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 receivce
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).

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

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index de19c34..6bb138d 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 574cf05..35e886c 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -340,6 +340,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.
diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
index 6152d04..cac1406 100644
--- a/virt/kvm/arm/its-emul.h
+++ b/virt/kvm/arm/its-emul.h
@@ -33,6 +33,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 66640c2fa..4513551 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -901,6 +901,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] 104+ messages in thread

* [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
  2015-05-29  9:53 ` Andre Przywara
@ 2015-05-29  9:53   ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 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 +
 include/kvm/arm_vgic.h            | 10 ++++++++++
 virt/kvm/arm/its-emul.c           |  9 ++++++++-
 virt/kvm/arm/vgic-v3-emul.c       | 20 +++++++++++++++-----
 virt/kvm/arm/vgic.c               | 10 ++++++++++
 6 files changed, 45 insertions(+), 7 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 891d64a..d20fd94 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2108,7 +2108,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 5105e29..6c432c0 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -30,6 +30,7 @@ config KVM
 	select SRCU
 	select HAVE_KVM_EVENTFD
 	select HAVE_KVM_IRQFD
+	select HAVE_KVM_MSI
 	---help---
 	  Support hosting virtualized guest machines.
 
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 6bb138d..8f1be6a 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;
@@ -365,4 +366,13 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
 }
 #endif
 
+#ifdef CONFIG_HAVE_KVM_MSI
+int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
+#else
+static inline int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
+{
+	return -ENODEV;
+}
+#endif
+
 #endif
diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index 35e886c..864de19 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -964,6 +964,7 @@ int vits_init(struct kvm *kvm)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
 	struct vgic_its *its = &dist->its;
+	int ret;
 
 	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
 		return -ENXIO;
@@ -977,9 +978,15 @@ 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;
 
-	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 4513551..71d0bcf 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -89,10 +89,11 @@ 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
+#define INTERRUPT_ID_BITS_ITS 16
 static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
 			      struct kvm_exit_mmio *mmio, phys_addr_t offset)
 {
@@ -100,7 +101,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);
@@ -519,7 +525,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 */
+		dist->lpis_enabled = true;
+		vgic_enable_lpis(vcpu);
+		return true;
 	}
 	return false;
 }
@@ -546,6 +554,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 9f7b05f..09b1f46 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -2254,3 +2254,13 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
 {
 	return 0;
 }
+
+#ifdef CONFIG_HAVE_KVM_MSI
+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;
+}
+#endif
-- 
2.3.5

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

* [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
@ 2015-05-29  9:53   ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-05-29  9:53 UTC (permalink / raw)
  To: christoffer.dall, marc.zyngier; +Cc: kvmarm, linux-arm-kernel, kvm

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 +
 include/kvm/arm_vgic.h            | 10 ++++++++++
 virt/kvm/arm/its-emul.c           |  9 ++++++++-
 virt/kvm/arm/vgic-v3-emul.c       | 20 +++++++++++++++-----
 virt/kvm/arm/vgic.c               | 10 ++++++++++
 6 files changed, 45 insertions(+), 7 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 891d64a..d20fd94 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2108,7 +2108,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 5105e29..6c432c0 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -30,6 +30,7 @@ config KVM
 	select SRCU
 	select HAVE_KVM_EVENTFD
 	select HAVE_KVM_IRQFD
+	select HAVE_KVM_MSI
 	---help---
 	  Support hosting virtualized guest machines.
 
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 6bb138d..8f1be6a 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;
@@ -365,4 +366,13 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
 }
 #endif
 
+#ifdef CONFIG_HAVE_KVM_MSI
+int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
+#else
+static inline int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
+{
+	return -ENODEV;
+}
+#endif
+
 #endif
diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
index 35e886c..864de19 100644
--- a/virt/kvm/arm/its-emul.c
+++ b/virt/kvm/arm/its-emul.c
@@ -964,6 +964,7 @@ int vits_init(struct kvm *kvm)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
 	struct vgic_its *its = &dist->its;
+	int ret;
 
 	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
 		return -ENXIO;
@@ -977,9 +978,15 @@ 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;
 
-	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 4513551..71d0bcf 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -89,10 +89,11 @@ 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
+#define INTERRUPT_ID_BITS_ITS 16
 static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
 			      struct kvm_exit_mmio *mmio, phys_addr_t offset)
 {
@@ -100,7 +101,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);
@@ -519,7 +525,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 */
+		dist->lpis_enabled = true;
+		vgic_enable_lpis(vcpu);
+		return true;
 	}
 	return false;
 }
@@ -546,6 +554,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 9f7b05f..09b1f46 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -2254,3 +2254,13 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
 {
 	return 0;
 }
+
+#ifdef CONFIG_HAVE_KVM_MSI
+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;
+}
+#endif
-- 
2.3.5

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

* [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
  2015-05-29  9:53 ` Andre Przywara
@ 2015-06-08  6:53   ` Pavel Fedin
  -1 siblings, 0 replies; 104+ messages in thread
From: Pavel Fedin @ 2015-06-08  6:53 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello everybody!

> The GICv3 ITS (Interrupt Translation Service) is a part of the
> ARM GICv3 interrupt controller 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.

 I have tested the patch and got some more ideas for future extension...

 First of all, it would be nice to have a possibility to directly inject LPIs by number.
This will be useful for irqfd support in qemu.
 Next, irqfd support currently poses a problem. We need to somehow know IRQ number from
MSI-X data (device ID plus event ID). ITS has all this information, so it would be nice to
be able to query for the translation from within userspace. The question is - how to do
it? Should we add some ioctl for this purpose? Currently i am experimenting with extra
KVM_TRANSLATE_MSI ioctl which, given MSI data, would return LPI number.
 Actually before your patch came out i have almost done the same thing. But instead i
decided to implement ITS in qemu while leaving LPI handling to kernel. In this case my
qemu would have everything needed.
 By the way, why did you decide to put everything into kernel? Yes, in-kernel emulation is
faster, but ITS is not accessed frequently.

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

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

* RE: [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
@ 2015-06-08  6:53   ` Pavel Fedin
  0 siblings, 0 replies; 104+ messages in thread
From: Pavel Fedin @ 2015-06-08  6:53 UTC (permalink / raw)
  To: 'Andre Przywara', christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

 Hello everybody!

> The GICv3 ITS (Interrupt Translation Service) is a part of the
> ARM GICv3 interrupt controller 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.

 I have tested the patch and got some more ideas for future extension...

 First of all, it would be nice to have a possibility to directly inject LPIs by number.
This will be useful for irqfd support in qemu.
 Next, irqfd support currently poses a problem. We need to somehow know IRQ number from
MSI-X data (device ID plus event ID). ITS has all this information, so it would be nice to
be able to query for the translation from within userspace. The question is - how to do
it? Should we add some ioctl for this purpose? Currently i am experimenting with extra
KVM_TRANSLATE_MSI ioctl which, given MSI data, would return LPI number.
 Actually before your patch came out i have almost done the same thing. But instead i
decided to implement ITS in qemu while leaving LPI handling to kernel. In this case my
qemu would have everything needed.
 By the way, why did you decide to put everything into kernel? Yes, in-kernel emulation is
faster, but ITS is not accessed frequently.

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

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

* [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
  2015-06-08  6:53   ` Pavel Fedin
@ 2015-06-08  8:23     ` Marc Zyngier
  -1 siblings, 0 replies; 104+ messages in thread
From: Marc Zyngier @ 2015-06-08  8:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Pavel,

On 08/06/15 07:53, Pavel Fedin wrote:
>  Hello everybody!
> 
>> The GICv3 ITS (Interrupt Translation Service) is a part of the
>> ARM GICv3 interrupt controller 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.
> 
>  I have tested the patch and got some more ideas for future extension...
> 
>  First of all, it would be nice to have a possibility to directly inject LPIs by number.
> This will be useful for irqfd support in qemu.

Well, that poses the question of what we emulate. We expose the
emulation of an ITS, hence no direct access to the LPI space. What we
could do would be allow LPI injection if not ITS is instantiated in the
kernel. But a mix of the two is likely to in contradiction with the
architecture.

>  Next, irqfd support currently poses a problem. We need to somehow know IRQ number from
> MSI-X data (device ID plus event ID). ITS has all this information, so it would be nice to
> be able to query for the translation from within userspace. The question is - how to do
> it? Should we add some ioctl for this purpose? Currently i am experimenting with extra
> KVM_TRANSLATE_MSI ioctl which, given MSI data, would return LPI number.

I'm afraid this is not enough. A write to GICR_TRANSLATER (DID+EID)
results in a (LPI,CPU) pair. Can you easily express the CPU part in
irqfd (this is a genuine question, I'm not familiar enough with that
part of the core)?

>  Actually before your patch came out i have almost done the same thing. But instead i
> decided to implement ITS in qemu while leaving LPI handling to kernel. In this case my
> qemu would have everything needed.
>  By the way, why did you decide to put everything into kernel? Yes, in-kernel emulation is
> faster, but ITS is not accessed frequently.

It may be interesting to find out what would be the implications if we
were to put it in userspace.

The obvious one would be that we'd have to duplicate the code in both
QEMU and kvmtool, and I don't think anyone fancies that. Another concern
would be the support of GICv4, which relies on the command queue
handling to be handled in the kernel (the GICv4 handling is basically a
command translation system, and I'm not prepared to let userspace inject
commands in the host ITS).

Thanks,

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

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

* Re: [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
@ 2015-06-08  8:23     ` Marc Zyngier
  0 siblings, 0 replies; 104+ messages in thread
From: Marc Zyngier @ 2015-06-08  8:23 UTC (permalink / raw)
  To: Pavel Fedin, Andre Przywara, christoffer.dall@linaro.org
  Cc: kvmarm@lists.cs.columbia.edu,
	linux-arm-kernel@lists.infradead.org, kvm@vger.kernel.org

Hi Pavel,

On 08/06/15 07:53, Pavel Fedin wrote:
>  Hello everybody!
> 
>> The GICv3 ITS (Interrupt Translation Service) is a part of the
>> ARM GICv3 interrupt controller 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.
> 
>  I have tested the patch and got some more ideas for future extension...
> 
>  First of all, it would be nice to have a possibility to directly inject LPIs by number.
> This will be useful for irqfd support in qemu.

Well, that poses the question of what we emulate. We expose the
emulation of an ITS, hence no direct access to the LPI space. What we
could do would be allow LPI injection if not ITS is instantiated in the
kernel. But a mix of the two is likely to in contradiction with the
architecture.

>  Next, irqfd support currently poses a problem. We need to somehow know IRQ number from
> MSI-X data (device ID plus event ID). ITS has all this information, so it would be nice to
> be able to query for the translation from within userspace. The question is - how to do
> it? Should we add some ioctl for this purpose? Currently i am experimenting with extra
> KVM_TRANSLATE_MSI ioctl which, given MSI data, would return LPI number.

I'm afraid this is not enough. A write to GICR_TRANSLATER (DID+EID)
results in a (LPI,CPU) pair. Can you easily express the CPU part in
irqfd (this is a genuine question, I'm not familiar enough with that
part of the core)?

>  Actually before your patch came out i have almost done the same thing. But instead i
> decided to implement ITS in qemu while leaving LPI handling to kernel. In this case my
> qemu would have everything needed.
>  By the way, why did you decide to put everything into kernel? Yes, in-kernel emulation is
> faster, but ITS is not accessed frequently.

It may be interesting to find out what would be the implications if we
were to put it in userspace.

The obvious one would be that we'd have to duplicate the code in both
QEMU and kvmtool, and I don't think anyone fancies that. Another concern
would be the support of GICv4, which relies on the command queue
handling to be handled in the kernel (the GICv4 handling is basically a
command translation system, and I'm not prepared to let userspace inject
commands in the host ITS).

Thanks,

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

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

* [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
  2015-06-08  8:23     ` Marc Zyngier
@ 2015-06-08 10:54       ` Pavel Fedin
  -1 siblings, 0 replies; 104+ messages in thread
From: Pavel Fedin @ 2015-06-08 10:54 UTC (permalink / raw)
  To: linux-arm-kernel

 Hi!

> I'm afraid this is not enough. A write to GICR_TRANSLATER (DID+EID)
> results in a (LPI,CPU) pair. Can you easily express the CPU part in
> irqfd (this is a genuine question, I'm not familiar enough with that
> part of the core)?

 But... As far as i could understand, LPI is added to a collection as a part of setup. And
collection actually represents a destination CPU, doesn't it? And we can't have multiple
LPIs sharing the same number and going to different CPUs. Or am i wrong? Unfortunately i
don't have GICv3 arch reference manual.

> Another concern
> would be the support of GICv4, which relies on the command queue
> handling to be handled in the kernel

 Wow, i didn't know about GICv4.

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

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

* RE: [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
@ 2015-06-08 10:54       ` Pavel Fedin
  0 siblings, 0 replies; 104+ messages in thread
From: Pavel Fedin @ 2015-06-08 10:54 UTC (permalink / raw)
  To: 'Marc Zyngier', 'Andre Przywara',
	christoffer.dall
  Cc: kvmarm, linux-arm-kernel, kvm

 Hi!

> I'm afraid this is not enough. A write to GICR_TRANSLATER (DID+EID)
> results in a (LPI,CPU) pair. Can you easily express the CPU part in
> irqfd (this is a genuine question, I'm not familiar enough with that
> part of the core)?

 But... As far as i could understand, LPI is added to a collection as a part of setup. And
collection actually represents a destination CPU, doesn't it? And we can't have multiple
LPIs sharing the same number and going to different CPUs. Or am i wrong? Unfortunately i
don't have GICv3 arch reference manual.

> Another concern
> would be the support of GICv4, which relies on the command queue
> handling to be handled in the kernel

 Wow, i didn't know about GICv4.

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



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

* [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
  2015-06-08 10:54       ` Pavel Fedin
@ 2015-06-08 17:13         ` Marc Zyngier
  -1 siblings, 0 replies; 104+ messages in thread
From: Marc Zyngier @ 2015-06-08 17:13 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/06/15 11:54, Pavel Fedin wrote:
>  Hi!
> 
>> I'm afraid this is not enough. A write to GICR_TRANSLATER (DID+EID)
>> results in a (LPI,CPU) pair. Can you easily express the CPU part in
>> irqfd (this is a genuine question, I'm not familiar enough with that
>> part of the core)?
> 
>  But... As far as i could understand, LPI is added to a collection as a part of setup. And
> collection actually represents a destination CPU, doesn't it? And we can't have multiple
> LPIs sharing the same number and going to different CPUs. Or am i wrong? Unfortunately i
> don't have GICv3 arch reference manual.

This is true to some extent. But the point is that the result of the
translation is both an LPI and a CPU. My question was how you would
indicate convey the notion of a target vcpu when using irqfd. As far as
I know this doesn't really fit, unless we start introducing the dreaded
GSI routing...

Do we really want to go down that road?

>> Another concern
>> would be the support of GICv4, which relies on the command queue
>> handling to be handled in the kernel
> 
>  Wow, i didn't know about GICv4.

I wish I didn't know about it.

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

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

* Re: [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
@ 2015-06-08 17:13         ` Marc Zyngier
  0 siblings, 0 replies; 104+ messages in thread
From: Marc Zyngier @ 2015-06-08 17:13 UTC (permalink / raw)
  To: Pavel Fedin, Andre Przywara, christoffer.dall@linaro.org
  Cc: kvmarm@lists.cs.columbia.edu,
	linux-arm-kernel@lists.infradead.org, kvm@vger.kernel.org

On 08/06/15 11:54, Pavel Fedin wrote:
>  Hi!
> 
>> I'm afraid this is not enough. A write to GICR_TRANSLATER (DID+EID)
>> results in a (LPI,CPU) pair. Can you easily express the CPU part in
>> irqfd (this is a genuine question, I'm not familiar enough with that
>> part of the core)?
> 
>  But... As far as i could understand, LPI is added to a collection as a part of setup. And
> collection actually represents a destination CPU, doesn't it? And we can't have multiple
> LPIs sharing the same number and going to different CPUs. Or am i wrong? Unfortunately i
> don't have GICv3 arch reference manual.

This is true to some extent. But the point is that the result of the
translation is both an LPI and a CPU. My question was how you would
indicate convey the notion of a target vcpu when using irqfd. As far as
I know this doesn't really fit, unless we start introducing the dreaded
GSI routing...

Do we really want to go down that road?

>> Another concern
>> would be the support of GICv4, which relies on the command queue
>> handling to be handled in the kernel
> 
>  Wow, i didn't know about GICv4.

I wish I didn't know about it.

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

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

* [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
  2015-06-08 10:54       ` Pavel Fedin
@ 2015-06-09  8:12         ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  8:12 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/08/2015 12:54 PM, Pavel Fedin wrote:
>  Hi!
> 
>> I'm afraid this is not enough. A write to GICR_TRANSLATER (DID+EID)
>> results in a (LPI,CPU) pair. Can you easily express the CPU part in
>> irqfd (this is a genuine question, I'm not familiar enough with that
>> part of the core)?

Currently on ARM, irqfd supports routing an host eventfd towards a
virtual SPI:
eventfd -> vSPI = gsi+32
parameters of irqfd are the eventfd and the gsi.

We do not implement KVM IRQ routing yet. This IRQ routing supports 2 modes:
1) irqchip routing: eventfd -> virtual gsi -> virtual irqchip.input pin
2) msi routing: eventfd -> virtual gsi -> virtual msi (@, data)

1) up to now we had a single virtual irqchip, vgicv2 or vgicv3 (no apic
as in x86, ...) so irqchip routing did not sound to be helpful
2) now we have virtual msi injection, we could use msi routing to inject
virtual LPI's. But is it what you need for your qemu integration?

Currently on QEMU side for VIRTIO-PCI with vhost back-end + GICv2m +
irqfd, so called kvm_gsi_direct_mapping is used:
the MSI data is extracted from the PCI virtio device MSI vector, the
virtual gsi = MSI data - 32 and eventually irqfd is programmed with the
eventfd and the gsi. That way MSI injection on guest is bypassed in
irqfd mode.

Please let us know

Best Regards

Eric
> 
>  But... As far as i could understand, LPI is added to a collection as a part of setup. And
> collection actually represents a destination CPU, doesn't it? And we can't have multiple
> LPIs sharing the same number and going to different CPUs. Or am i wrong? Unfortunately i
> don't have GICv3 arch reference manual.
> 
>> Another concern
>> would be the support of GICv4, which relies on the command queue
>> handling to be handled in the kernel
> 
>  Wow, i didn't know about GICv4.
> 
> 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] 104+ messages in thread

* Re: [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
@ 2015-06-09  8:12         ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  8:12 UTC (permalink / raw)
  To: Pavel Fedin, 'Marc Zyngier', 'Andre Przywara',
	christoffer.dall
  Cc: kvmarm, linux-arm-kernel, kvm

On 06/08/2015 12:54 PM, Pavel Fedin wrote:
>  Hi!
> 
>> I'm afraid this is not enough. A write to GICR_TRANSLATER (DID+EID)
>> results in a (LPI,CPU) pair. Can you easily express the CPU part in
>> irqfd (this is a genuine question, I'm not familiar enough with that
>> part of the core)?

Currently on ARM, irqfd supports routing an host eventfd towards a
virtual SPI:
eventfd -> vSPI = gsi+32
parameters of irqfd are the eventfd and the gsi.

We do not implement KVM IRQ routing yet. This IRQ routing supports 2 modes:
1) irqchip routing: eventfd -> virtual gsi -> virtual irqchip.input pin
2) msi routing: eventfd -> virtual gsi -> virtual msi (@, data)

1) up to now we had a single virtual irqchip, vgicv2 or vgicv3 (no apic
as in x86, ...) so irqchip routing did not sound to be helpful
2) now we have virtual msi injection, we could use msi routing to inject
virtual LPI's. But is it what you need for your qemu integration?

Currently on QEMU side for VIRTIO-PCI with vhost back-end + GICv2m +
irqfd, so called kvm_gsi_direct_mapping is used:
the MSI data is extracted from the PCI virtio device MSI vector, the
virtual gsi = MSI data - 32 and eventually irqfd is programmed with the
eventfd and the gsi. That way MSI injection on guest is bypassed in
irqfd mode.

Please let us know

Best Regards

Eric
> 
>  But... As far as i could understand, LPI is added to a collection as a part of setup. And
> collection actually represents a destination CPU, doesn't it? And we can't have multiple
> LPIs sharing the same number and going to different CPUs. Or am i wrong? Unfortunately i
> don't have GICv3 arch reference manual.
> 
>> Another concern
>> would be the support of GICv4, which relies on the command queue
>> handling to be handled in the kernel
> 
>  Wow, i didn't know about GICv4.
> 
> 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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


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

* [PATCH 02/13] KVM: extend struct kvm_msi to hold a 32-bit device ID
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-09  8:49     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

Reviewed-by: Eric Auger <eric.auger@linaro.org>
On 05/29/2015 11:53 AM, Andre Przywara wrote:
> 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.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  Documentation/virtual/kvm/api.txt | 8 ++++++--
>  include/uapi/linux/kvm.h          | 4 +++-
>  2 files changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 9fa2bf8..891d64a 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2121,10 +2121,14 @@ 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 is valid, otherwise ignored.
> +devid: If KVM_MSI_VALID_DEVID is set, contains a value to identify the device
> +       that wrote the MSI message. For PCI, this is usually a BFD
> +       identifier in the lower 16 bits.
>  
>  
>  4.71 KVM_CREATE_PIT2
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 4b60056..2a23705 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -965,12 +965,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 {
> 

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

* Re: [PATCH 02/13] KVM: extend struct kvm_msi to hold a 32-bit device ID
@ 2015-06-09  8:49     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  8:49 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

Reviewed-by: Eric Auger <eric.auger@linaro.org>
On 05/29/2015 11:53 AM, Andre Przywara wrote:
> 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.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  Documentation/virtual/kvm/api.txt | 8 ++++++--
>  include/uapi/linux/kvm.h          | 4 +++-
>  2 files changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 9fa2bf8..891d64a 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2121,10 +2121,14 @@ 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 is valid, otherwise ignored.
> +devid: If KVM_MSI_VALID_DEVID is set, contains a value to identify the device
> +       that wrote the MSI message. For PCI, this is usually a BFD
> +       identifier in the lower 16 bits.
>  
>  
>  4.71 KVM_CREATE_PIT2
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 4b60056..2a23705 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -965,12 +965,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 {
> 


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

* [PATCH 03/13] KVM: arm/arm64: add emulation model specific destroy function
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-09  8:51     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  8:51 UTC (permalink / raw)
  To: linux-arm-kernel

Reviewed-by: Eric Auger <eric.auger@linaro.org>
On 05/29/2015 11:53 AM, Andre Przywara wrote:
> Currently we destroy the VGIC emulation in one function that cares for
> all emulated models. The ITS emulation will require some
> differentiation, so introduce a per-emulation-model destroy method.
> Use it for a tiny GICv3 specific code already.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  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 e9c3a7a..fbfdd6f 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -818,6 +818,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)
>  {
> @@ -830,6 +838,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 037b723..6ea30e0 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -102,6 +102,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.
> @@ -1631,6 +1639,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);
>  
> @@ -1647,7 +1657,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);
> 

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

* Re: [PATCH 03/13] KVM: arm/arm64: add emulation model specific destroy function
@ 2015-06-09  8:51     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  8:51 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

Reviewed-by: Eric Auger <eric.auger@linaro.org>
On 05/29/2015 11:53 AM, Andre Przywara wrote:
> Currently we destroy the VGIC emulation in one function that cares for
> all emulated models. The ITS emulation will require some
> differentiation, so introduce a per-emulation-model destroy method.
> Use it for a tiny GICv3 specific code already.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  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 e9c3a7a..fbfdd6f 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -818,6 +818,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)
>  {
> @@ -830,6 +838,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 037b723..6ea30e0 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -102,6 +102,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.
> @@ -1631,6 +1639,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);
>  
> @@ -1647,7 +1657,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);
> 


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

* [PATCH 04/13] KVM: arm64: Introduce new MMIO region for the ITS base address
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-09  8:52     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  8:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/29/2015 11:53 AM, 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 |  7 +++++++
>  arch/arm64/include/uapi/asm/kvm.h              |  3 +++
>  include/kvm/arm_vgic.h                         |  3 +++
>  virt/kvm/arm/vgic-v3-emul.c                    |  1 +
>  virt/kvm/arm/vgic.c                            | 17 +++++++++++++++++
>  virt/kvm/arm/vgic.h                            |  1 +
>  6 files changed, 32 insertions(+)
> 
> diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
> index 3fb9054..1f89001 100644
> --- a/Documentation/virtual/kvm/devices/arm-vgic.txt
> +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt
> @@ -39,6 +39,13 @@ 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
> +      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.
> +      Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
> +      This address needs to be 64K aligned and the region covers 64 KByte.
I would emphasize this is the control registers (ITS_Base) hence a
single page, not comprising the ITS translation register page.
>  
>    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..e42435c 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -82,8 +82,11 @@ struct kvm_regs {
>  #define KVM_VGIC_V3_ADDR_TYPE_DIST	2
>  #define KVM_VGIC_V3_ADDR_TYPE_REDIST	3
>  
extra white line?
> +#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..37725bb 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 for the MSI control block (V2M/ITS) */
why V2M here? It's it the GITS_TRANSLATER page that has a fellow page in
case of V2M?
> +	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 fbfdd6f..16c6d8a 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -1012,6 +1012,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 6ea30e0..2e9723aa 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -932,6 +932,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;
> @@ -1835,6 +1845,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
>  	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;
> +	kvm->arch.vgic.vgic_its_base = VGIC_ADDR_UNDEF;
minor: given the fact we have specialized
init_vgic_model/vgic_vx_init_emulation wouldn't it make sense to move
those VGIC v3 specific assignment there? also CPU base is specific to v2?

Eric
>  
>  out_unlock:
>  	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
> @@ -1932,6 +1943,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] 104+ messages in thread

* Re: [PATCH 04/13] KVM: arm64: Introduce new MMIO region for the ITS base address
@ 2015-06-09  8:52     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  8:52 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

On 05/29/2015 11:53 AM, 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 |  7 +++++++
>  arch/arm64/include/uapi/asm/kvm.h              |  3 +++
>  include/kvm/arm_vgic.h                         |  3 +++
>  virt/kvm/arm/vgic-v3-emul.c                    |  1 +
>  virt/kvm/arm/vgic.c                            | 17 +++++++++++++++++
>  virt/kvm/arm/vgic.h                            |  1 +
>  6 files changed, 32 insertions(+)
> 
> diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
> index 3fb9054..1f89001 100644
> --- a/Documentation/virtual/kvm/devices/arm-vgic.txt
> +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt
> @@ -39,6 +39,13 @@ 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
> +      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.
> +      Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
> +      This address needs to be 64K aligned and the region covers 64 KByte.
I would emphasize this is the control registers (ITS_Base) hence a
single page, not comprising the ITS translation register page.
>  
>    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..e42435c 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -82,8 +82,11 @@ struct kvm_regs {
>  #define KVM_VGIC_V3_ADDR_TYPE_DIST	2
>  #define KVM_VGIC_V3_ADDR_TYPE_REDIST	3
>  
extra white line?
> +#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..37725bb 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 for the MSI control block (V2M/ITS) */
why V2M here? It's it the GITS_TRANSLATER page that has a fellow page in
case of V2M?
> +	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 fbfdd6f..16c6d8a 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -1012,6 +1012,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 6ea30e0..2e9723aa 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -932,6 +932,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;
> @@ -1835,6 +1845,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
>  	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;
> +	kvm->arch.vgic.vgic_its_base = VGIC_ADDR_UNDEF;
minor: given the fact we have specialized
init_vgic_model/vgic_vx_init_emulation wouldn't it make sense to move
those VGIC v3 specific assignment there? also CPU base is specific to v2?

Eric
>  
>  out_unlock:
>  	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
> @@ -1932,6 +1943,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] 104+ messages in thread

* [PATCH 05/13] KVM: arm64: handle ITS related GICv3 redistributor registers
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-09  8:52     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  8:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/29/2015 11:53 AM, 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      |  4 ++++
>  virt/kvm/arm/vgic-v3-emul.c | 43 +++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic.c         | 35 +++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic.h         |  4 ++++
>  4 files changed, 86 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 37725bb..9ea0b3b 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -256,6 +256,10 @@ struct vgic_dist {
>  	struct vgic_vm_ops	vm_ops;
>  	struct vgic_io_device	dist_iodev;
>  	struct vgic_io_device	*redist_iodevs;
> +
add some comments?
/* LPI config table shared by all distributors */
> +	u64			propbaser;
/* LPI pending table per distributors */
> +	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 16c6d8a..04f3aed 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -607,6 +607,37 @@ 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;
> +
you may add the same comment as below?
> +	mode |= dist->lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
> +	vgic_handle_base_register(vcpu, mmio, offset, &dist->propbaser, mode);
having the PROPBASER programmed to different values on different redist
with EnableLPIs==1 also is unpredictable. Do we plan to check that
somewhere? Allow a single write?
> +
> +	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);
pendbaser is not yet allocated. Wouldn't it make sense to introduce that
patch later on?

Eric
> +
> +	return false;
> +}
> +
>  #define SGI_base(x) ((x) + SZ_64K)
>  
>  static const struct vgic_io_range vgic_redist_ranges[] = {
> @@ -635,6 +666,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 2e9723aa..0a9236d 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -448,6 +448,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)
> 

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

* Re: [PATCH 05/13] KVM: arm64: handle ITS related GICv3 redistributor registers
@ 2015-06-09  8:52     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  8:52 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

On 05/29/2015 11:53 AM, 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      |  4 ++++
>  virt/kvm/arm/vgic-v3-emul.c | 43 +++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic.c         | 35 +++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic.h         |  4 ++++
>  4 files changed, 86 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 37725bb..9ea0b3b 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -256,6 +256,10 @@ struct vgic_dist {
>  	struct vgic_vm_ops	vm_ops;
>  	struct vgic_io_device	dist_iodev;
>  	struct vgic_io_device	*redist_iodevs;
> +
add some comments?
/* LPI config table shared by all distributors */
> +	u64			propbaser;
/* LPI pending table per distributors */
> +	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 16c6d8a..04f3aed 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -607,6 +607,37 @@ 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;
> +
you may add the same comment as below?
> +	mode |= dist->lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
> +	vgic_handle_base_register(vcpu, mmio, offset, &dist->propbaser, mode);
having the PROPBASER programmed to different values on different redist
with EnableLPIs==1 also is unpredictable. Do we plan to check that
somewhere? Allow a single write?
> +
> +	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);
pendbaser is not yet allocated. Wouldn't it make sense to introduce that
patch later on?

Eric
> +
> +	return false;
> +}
> +
>  #define SGI_base(x) ((x) + SZ_64K)
>  
>  static const struct vgic_io_range vgic_redist_ranges[] = {
> @@ -635,6 +666,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 2e9723aa..0a9236d 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -448,6 +448,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)
> 


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

* [PATCH 06/13] KVM: arm64: introduce ITS emulation file with stub functions
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-09  9:23     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  9:23 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/29/2015 11:53 AM, 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 skeletton with function stubs to be filled later.
skeleton
> 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            | 127 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h            |  35 ++++++++++
>  virt/kvm/arm/vgic-v3-emul.c        |  22 ++++++-
>  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 d5904f8..0d09189 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 9ea0b3b..d76c2d9 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;
> @@ -260,6 +265,7 @@ struct vgic_dist {
>  	u64			propbaser;
>  	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..7b283ce
> --- /dev/null
> +++ b/virt/kvm/arm/its-emul.c
> @@ -0,0 +1,127 @@
> +/*
> + * 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,
> +	},
> +};
> +
> +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;
> +
> +	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
> +		return -ENXIO;
> +
> +	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 04f3aed..4e40684 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)
> @@ -506,9 +507,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;
>  }
Can't you move above addition in "KVM: arm64: handle ITS related GICv3
redistributor registers" in case this latter is moved?

Eric
>  
> @@ -816,6 +828,10 @@ static int vgic_v3_map_resources(struct kvm *kvm,
>  		rdbase += GIC_V3_REDIST_SIZE;
>  	}
>  
> +	ret = vits_init(kvm);
> +	if (ret && ret != -ENXIO)
> +		goto out_unregister;
> +
>  	dist->redist_iodevs = iodevs;
>  	dist->ready = true;
>  	goto out;
> 

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

* Re: [PATCH 06/13] KVM: arm64: introduce ITS emulation file with stub functions
@ 2015-06-09  9:23     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09  9:23 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

On 05/29/2015 11:53 AM, 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 skeletton with function stubs to be filled later.
skeleton
> 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            | 127 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h            |  35 ++++++++++
>  virt/kvm/arm/vgic-v3-emul.c        |  22 ++++++-
>  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 d5904f8..0d09189 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 9ea0b3b..d76c2d9 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;
> @@ -260,6 +265,7 @@ struct vgic_dist {
>  	u64			propbaser;
>  	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..7b283ce
> --- /dev/null
> +++ b/virt/kvm/arm/its-emul.c
> @@ -0,0 +1,127 @@
> +/*
> + * 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,
> +	},
> +};
> +
> +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;
> +
> +	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
> +		return -ENXIO;
> +
> +	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 04f3aed..4e40684 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)
> @@ -506,9 +507,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;
>  }
Can't you move above addition in "KVM: arm64: handle ITS related GICv3
redistributor registers" in case this latter is moved?

Eric
>  
> @@ -816,6 +828,10 @@ static int vgic_v3_map_resources(struct kvm *kvm,
>  		rdbase += GIC_V3_REDIST_SIZE;
>  	}
>  
> +	ret = vits_init(kvm);
> +	if (ret && ret != -ENXIO)
> +		goto out_unregister;
> +
>  	dist->redist_iodevs = iodevs;
>  	dist->ready = true;
>  	goto out;
> 


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

* [PATCH 07/13] KVM: arm64: implement basic ITS register handlers
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-09 13:34     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09 13:34 UTC (permalink / raw)
  To: linux-arm-kernel

Reviewed-by: Eric Auger <eric.auger@linaro.org>
On 05/29/2015 11:53 AM, 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,CREAD,CWRITER}
CREADR
>   those implement the ITS command buffer handling
> 
> 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            | 172 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h            |   1 +
>  virt/kvm/arm/vgic-v3-emul.c        |   2 +
>  5 files changed, 186 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index d76c2d9..3b8e3a1 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 7b283ce..82bc34a 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)
> +
> +/* distributor lock is hold 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,107 @@ 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);
> +	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);
> +}
> +
>  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;
> +	u64 cmd_buf[4];
> +	gpa_t cbaser = its_cmd_buffer_base(vcpu->kvm);
> +	u32 reg;
> +	int ret;
> +
> +	spin_lock(&its->lock);
> +	switch (offset & ~3) {
> +	case 0x00:
> +		reg = its->cwriter & 0xfffe0;
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
> +		reg &= 0xfffe0;
> +		if (reg > its_cmd_buffer_size(vcpu->kvm))
> +			break;
> +		while (its->creadr != reg) {
> +			ret = kvm_read_guest(vcpu->kvm, cbaser + its->creadr,
> +					     cmd_buf, 32);
> +			if (ret)
> +				break;
> +			vits_handle_command(vcpu, cmd_buf);
> +			its->creadr += 32;
> +			if (its->creadr == its_cmd_buffer_size(vcpu->kvm))
> +				its->creadr = 0;
> +		}
> +		its->cwriter = reg;
> +		break;
> +	case 0x04:
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
> +		break;
> +	}
> +	spin_unlock(&its->lock);
>  	return false;
>  }
>  
> @@ -64,6 +203,22 @@ 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;
> +
> +	spin_lock(&its->lock);
> +	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;
> +	}
> +	spin_unlock(&its->lock);
>  	return false;
>  }
>  
> @@ -119,9 +274,26 @@ int vits_init(struct kvm *kvm)
>  	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
>  		return -ENXIO;
>  
> +	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 4e40684..fa81c4b 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -881,6 +881,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] 104+ messages in thread

* Re: [PATCH 07/13] KVM: arm64: implement basic ITS register handlers
@ 2015-06-09 13:34     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09 13:34 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

Reviewed-by: Eric Auger <eric.auger@linaro.org>
On 05/29/2015 11:53 AM, 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,CREAD,CWRITER}
CREADR
>   those implement the ITS command buffer handling
> 
> 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            | 172 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h            |   1 +
>  virt/kvm/arm/vgic-v3-emul.c        |   2 +
>  5 files changed, 186 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index d76c2d9..3b8e3a1 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 7b283ce..82bc34a 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)
> +
> +/* distributor lock is hold 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,107 @@ 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);
> +	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);
> +}
> +
>  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;
> +	u64 cmd_buf[4];
> +	gpa_t cbaser = its_cmd_buffer_base(vcpu->kvm);
> +	u32 reg;
> +	int ret;
> +
> +	spin_lock(&its->lock);
> +	switch (offset & ~3) {
> +	case 0x00:
> +		reg = its->cwriter & 0xfffe0;
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
> +		reg &= 0xfffe0;
> +		if (reg > its_cmd_buffer_size(vcpu->kvm))
> +			break;
> +		while (its->creadr != reg) {
> +			ret = kvm_read_guest(vcpu->kvm, cbaser + its->creadr,
> +					     cmd_buf, 32);
> +			if (ret)
> +				break;
> +			vits_handle_command(vcpu, cmd_buf);
> +			its->creadr += 32;
> +			if (its->creadr == its_cmd_buffer_size(vcpu->kvm))
> +				its->creadr = 0;
> +		}
> +		its->cwriter = reg;
> +		break;
> +	case 0x04:
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
> +		break;
> +	}
> +	spin_unlock(&its->lock);
>  	return false;
>  }
>  
> @@ -64,6 +203,22 @@ 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;
> +
> +	spin_lock(&its->lock);
> +	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;
> +	}
> +	spin_unlock(&its->lock);
>  	return false;
>  }
>  
> @@ -119,9 +274,26 @@ int vits_init(struct kvm *kvm)
>  	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
>  		return -ENXIO;
>  
> +	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 4e40684..fa81c4b 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -881,6 +881,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] 104+ messages in thread

* [PATCH 09/13] KVM: arm64: handle pending bit for LPIs in ITS emulation
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-09 15:59     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/29/2015 11:53 AM, 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     | 66 +++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h     |  3 ++
>  virt/kvm/arm/vgic-v3-emul.c |  2 ++
>  virt/kvm/arm/vgic.c         | 68 +++++++++++++++++++++++++++++++++------------
>  5 files changed, 124 insertions(+), 17 deletions(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index fa17df6..de19c34 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 f0f4a9c..f75fb9e 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;
allocated in later patch. does not ease the review of the life cycle but
I guess it is accepted/acceptable.

Isn't it somehow redundant to have a bitmap here where the collection
already indicates the target cpu id on which the LPI is pending?

Eric
>  };
>  
> +#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)
>  
>  /* distributor lock is hold by the VGIC MMIO handler */
> @@ -145,6 +163,54 @@ 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;
> +
> +	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;
> +}
> +
> +/* is 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 fa81c4b..66640c2fa 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -901,6 +901,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;
>  
>  	kvm->arch.max_vcpus = KVM_MAX_VCPUS;
>  }
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index 0a9236d..9f7b05f 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -97,6 +97,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);
> @@ -1149,25 +1163,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);
>  }
> @@ -1179,7 +1201,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;
> @@ -1187,7 +1208,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);
>  
> @@ -1267,8 +1287,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) {
> @@ -1389,6 +1413,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;
>  
> @@ -1413,7 +1447,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] 104+ messages in thread

* Re: [PATCH 09/13] KVM: arm64: handle pending bit for LPIs in ITS emulation
@ 2015-06-09 15:59     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09 15:59 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

On 05/29/2015 11:53 AM, 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     | 66 +++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h     |  3 ++
>  virt/kvm/arm/vgic-v3-emul.c |  2 ++
>  virt/kvm/arm/vgic.c         | 68 +++++++++++++++++++++++++++++++++------------
>  5 files changed, 124 insertions(+), 17 deletions(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index fa17df6..de19c34 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 f0f4a9c..f75fb9e 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;
allocated in later patch. does not ease the review of the life cycle but
I guess it is accepted/acceptable.

Isn't it somehow redundant to have a bitmap here where the collection
already indicates the target cpu id on which the LPI is pending?

Eric
>  };
>  
> +#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)
>  
>  /* distributor lock is hold by the VGIC MMIO handler */
> @@ -145,6 +163,54 @@ 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;
> +
> +	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;
> +}
> +
> +/* is 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 fa81c4b..66640c2fa 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -901,6 +901,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;
>  
>  	kvm->arch.max_vcpus = KVM_MAX_VCPUS;
>  }
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index 0a9236d..9f7b05f 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -97,6 +97,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);
> @@ -1149,25 +1163,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);
>  }
> @@ -1179,7 +1201,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;
> @@ -1187,7 +1208,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);
>  
> @@ -1267,8 +1287,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) {
> @@ -1389,6 +1413,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;
>  
> @@ -1413,7 +1447,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] 104+ messages in thread

* [PATCH 08/13] KVM: arm64: add data structures to model ITS interrupt translation
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-09 15:59     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

Reviewed-by: Eric Auger <eric.auger@linaro.org>
On 05/29/2015 11:53 AM, 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
> the lists becomes painful, 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 | 45 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 48 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 3b8e3a1..fa17df6 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 82bc34a..f0f4a9c 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)
>  
>  /* distributor lock is hold by the VGIC MMIO handler */
> @@ -280,6 +300,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;
> @@ -289,11 +312,33 @@ 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;
>  
> +	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);
>  }
> 

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

* Re: [PATCH 08/13] KVM: arm64: add data structures to model ITS interrupt translation
@ 2015-06-09 15:59     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-09 15:59 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

Reviewed-by: Eric Auger <eric.auger@linaro.org>
On 05/29/2015 11:53 AM, 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
> the lists becomes painful, 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 | 45 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 48 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 3b8e3a1..fa17df6 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 82bc34a..f0f4a9c 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)
>  
>  /* distributor lock is hold by the VGIC MMIO handler */
> @@ -280,6 +300,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;
> @@ -289,11 +312,33 @@ 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;
>  
> +	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);
>  }
> 


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

* RE: [PATCH 00/13] arm64: KVM: GICv3 ITS emulation
  2015-05-29  9:53 ` Andre Przywara
                   ` (14 preceding siblings ...)
  (?)
@ 2015-06-10 12:18 ` Pavel Fedin
  -1 siblings, 0 replies; 104+ messages in thread
From: Pavel Fedin @ 2015-06-10 12:18 UTC (permalink / raw)
  To: 'Andre Przywara', christoffer.dall, marc.zyngier; +Cc: kvm

 Hi! I have researched the promised third bug in your implementation. It reproduces if you
start qemu with -S switch, and then immediately exit it without actually running the OS.
 In KVM vGIC initialization is lazy and performed when first vCPU is booted up for the
first time. Consequently, if you never do it but attempt to quit qemu, KVM will go through
the complete shutdown process and call vits_destroy(), which will crash in
list_for_each_safe() because its->device_list was never initialized.
 For a quick fix i have added this:
--- cut ---
	if (!its->device_list.next)
		return;
--- cut ---

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



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

* [PATCH 04/13] KVM: arm64: Introduce new MMIO region for the ITS base address
  2015-06-09  8:52     ` Eric Auger
@ 2015-06-11 15:12       ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-11 15:12 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

thanks for the review!

On 06/09/2015 09:52 AM, Eric Auger wrote:
> On 05/29/2015 11:53 AM, 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 |  7 +++++++
>>  arch/arm64/include/uapi/asm/kvm.h              |  3 +++
>>  include/kvm/arm_vgic.h                         |  3 +++
>>  virt/kvm/arm/vgic-v3-emul.c                    |  1 +
>>  virt/kvm/arm/vgic.c                            | 17 +++++++++++++++++
>>  virt/kvm/arm/vgic.h                            |  1 +
>>  6 files changed, 32 insertions(+)
>>
>> diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
>> index 3fb9054..1f89001 100644
>> --- a/Documentation/virtual/kvm/devices/arm-vgic.txt
>> +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt
>> @@ -39,6 +39,13 @@ 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
>> +      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.
>> +      Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
>> +      This address needs to be 64K aligned and the region covers 64 KByte.
> I would emphasize this is the control registers (ITS_Base) hence a
> single page, not comprising the ITS translation register page.

Good point, will do.

>>  
>>    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..e42435c 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -82,8 +82,11 @@ struct kvm_regs {
>>  #define KVM_VGIC_V3_ADDR_TYPE_DIST	2
>>  #define KVM_VGIC_V3_ADDR_TYPE_REDIST	3
>>  
> extra white line?
>> +#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..37725bb 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 for the MSI control block (V2M/ITS) */
> why V2M here? It's it the GITS_TRANSLATER page that has a fellow page in
> case of V2M?

Ah yes, this was a leftover from a previous version of the series. I had
V2M in-kernel emulation implemented at some time, but later dropped that.
Thanks for spotting.

>> +	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 fbfdd6f..16c6d8a 100644
>> --- a/virt/kvm/arm/vgic-v3-emul.c
>> +++ b/virt/kvm/arm/vgic-v3-emul.c
>> @@ -1012,6 +1012,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 6ea30e0..2e9723aa 100644
>> --- a/virt/kvm/arm/vgic.c
>> +++ b/virt/kvm/arm/vgic.c
>> @@ -932,6 +932,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;
>> @@ -1835,6 +1845,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
>>  	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;
>> +	kvm->arch.vgic.vgic_its_base = VGIC_ADDR_UNDEF;
> minor: given the fact we have specialized
> init_vgic_model/vgic_vx_init_emulation wouldn't it make sense to move
> those VGIC v3 specific assignment there? also CPU base is specific to v2?

Yes, that seems to make some sense. The original idea was to make sure
that all of those addresses are properly initialized regardless of the
chosen guest model, but I see that this gets messy and would probably be
better solved by moving those assignments.

Thanks,
Andre.

>>  
>>  out_unlock:
>>  	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
>> @@ -1932,6 +1943,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] 104+ messages in thread

* Re: [PATCH 04/13] KVM: arm64: Introduce new MMIO region for the ITS base address
@ 2015-06-11 15:12       ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-11 15:12 UTC (permalink / raw)
  To: Eric Auger
  Cc: Marc Zyngier, kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu,
	linux-arm-kernel@lists.infradead.org

Hi Eric,

thanks for the review!

On 06/09/2015 09:52 AM, Eric Auger wrote:
> On 05/29/2015 11:53 AM, 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 |  7 +++++++
>>  arch/arm64/include/uapi/asm/kvm.h              |  3 +++
>>  include/kvm/arm_vgic.h                         |  3 +++
>>  virt/kvm/arm/vgic-v3-emul.c                    |  1 +
>>  virt/kvm/arm/vgic.c                            | 17 +++++++++++++++++
>>  virt/kvm/arm/vgic.h                            |  1 +
>>  6 files changed, 32 insertions(+)
>>
>> diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
>> index 3fb9054..1f89001 100644
>> --- a/Documentation/virtual/kvm/devices/arm-vgic.txt
>> +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt
>> @@ -39,6 +39,13 @@ 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
>> +      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.
>> +      Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
>> +      This address needs to be 64K aligned and the region covers 64 KByte.
> I would emphasize this is the control registers (ITS_Base) hence a
> single page, not comprising the ITS translation register page.

Good point, will do.

>>  
>>    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..e42435c 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -82,8 +82,11 @@ struct kvm_regs {
>>  #define KVM_VGIC_V3_ADDR_TYPE_DIST	2
>>  #define KVM_VGIC_V3_ADDR_TYPE_REDIST	3
>>  
> extra white line?
>> +#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..37725bb 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 for the MSI control block (V2M/ITS) */
> why V2M here? It's it the GITS_TRANSLATER page that has a fellow page in
> case of V2M?

Ah yes, this was a leftover from a previous version of the series. I had
V2M in-kernel emulation implemented at some time, but later dropped that.
Thanks for spotting.

>> +	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 fbfdd6f..16c6d8a 100644
>> --- a/virt/kvm/arm/vgic-v3-emul.c
>> +++ b/virt/kvm/arm/vgic-v3-emul.c
>> @@ -1012,6 +1012,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 6ea30e0..2e9723aa 100644
>> --- a/virt/kvm/arm/vgic.c
>> +++ b/virt/kvm/arm/vgic.c
>> @@ -932,6 +932,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;
>> @@ -1835,6 +1845,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
>>  	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;
>> +	kvm->arch.vgic.vgic_its_base = VGIC_ADDR_UNDEF;
> minor: given the fact we have specialized
> init_vgic_model/vgic_vx_init_emulation wouldn't it make sense to move
> those VGIC v3 specific assignment there? also CPU base is specific to v2?

Yes, that seems to make some sense. The original idea was to make sure
that all of those addresses are properly initialized regardless of the
chosen guest model, but I see that this gets messy and would probably be
better solved by moving those assignments.

Thanks,
Andre.

>>  
>>  out_unlock:
>>  	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
>> @@ -1932,6 +1943,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] 104+ messages in thread

* [PATCH 09/13] KVM: arm64: handle pending bit for LPIs in ITS emulation
  2015-06-09 15:59     ` Eric Auger
@ 2015-06-11 15:46       ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-11 15:46 UTC (permalink / raw)
  To: linux-arm-kernel

Salut Eric,

On 06/09/2015 04:59 PM, Eric Auger wrote:
> On 05/29/2015 11:53 AM, 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     | 66 +++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/its-emul.h     |  3 ++
>>  virt/kvm/arm/vgic-v3-emul.c |  2 ++
>>  virt/kvm/arm/vgic.c         | 68 +++++++++++++++++++++++++++++++++------------
>>  5 files changed, 124 insertions(+), 17 deletions(-)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index fa17df6..de19c34 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 f0f4a9c..f75fb9e 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;
> allocated in later patch. does not ease the review of the life cycle but
> I guess it is accepted/acceptable.

I tried to move some bits around a bit and ran into several issues, so I
guess we have to live with that.

> Isn't it somehow redundant to have a bitmap here where the collection
> already indicates the target cpu id on which the LPI is pending?

Unfortunately only "somewhat", as Marc taught me the other day ;-)
First, the spec shows that the pending bitmap is allocated _per CPU_, so
we have to model this here appropriately.
Second, you could have an LPI pending on one distributor, then change
the associated collection to another distributor and trigger that
interrupt again. This would make it pending on two VCPUs.
Admittedly not the most prominent use case, but possible.

Cheers,
Andre.

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

* Re: [PATCH 09/13] KVM: arm64: handle pending bit for LPIs in ITS emulation
@ 2015-06-11 15:46       ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-11 15:46 UTC (permalink / raw)
  To: Eric Auger
  Cc: Marc Zyngier, kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu,
	linux-arm-kernel@lists.infradead.org

Salut Eric,

On 06/09/2015 04:59 PM, Eric Auger wrote:
> On 05/29/2015 11:53 AM, 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     | 66 +++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/its-emul.h     |  3 ++
>>  virt/kvm/arm/vgic-v3-emul.c |  2 ++
>>  virt/kvm/arm/vgic.c         | 68 +++++++++++++++++++++++++++++++++------------
>>  5 files changed, 124 insertions(+), 17 deletions(-)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index fa17df6..de19c34 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 f0f4a9c..f75fb9e 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;
> allocated in later patch. does not ease the review of the life cycle but
> I guess it is accepted/acceptable.

I tried to move some bits around a bit and ran into several issues, so I
guess we have to live with that.

> Isn't it somehow redundant to have a bitmap here where the collection
> already indicates the target cpu id on which the LPI is pending?

Unfortunately only "somewhat", as Marc taught me the other day ;-)
First, the spec shows that the pending bitmap is allocated _per CPU_, so
we have to model this here appropriately.
Second, you could have an LPI pending on one distributor, then change
the associated collection to another distributor and trigger that
interrupt again. This would make it pending on two VCPUs.
Admittedly not the most prominent use case, but possible.

Cheers,
Andre.

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

* [PATCH 09/13] KVM: arm64: handle pending bit for LPIs in ITS emulation
  2015-06-11 15:46       ` Andre Przywara
@ 2015-06-11 16:01         ` Marc Zyngier
  -1 siblings, 0 replies; 104+ messages in thread
From: Marc Zyngier @ 2015-06-11 16:01 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/06/15 16:46, Andre Przywara wrote:
> Salut Eric,
> 
> On 06/09/2015 04:59 PM, Eric Auger wrote:
>> On 05/29/2015 11:53 AM, 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     | 66 +++++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/its-emul.h     |  3 ++
>>>  virt/kvm/arm/vgic-v3-emul.c |  2 ++
>>>  virt/kvm/arm/vgic.c         | 68 +++++++++++++++++++++++++++++++++------------
>>>  5 files changed, 124 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>> index fa17df6..de19c34 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 f0f4a9c..f75fb9e 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;
>> allocated in later patch. does not ease the review of the life cycle but
>> I guess it is accepted/acceptable.
> 
> I tried to move some bits around a bit and ran into several issues, so I
> guess we have to live with that.
> 
>> Isn't it somehow redundant to have a bitmap here where the collection
>> already indicates the target cpu id on which the LPI is pending?
> 
> Unfortunately only "somewhat", as Marc taught me the other day ;-)
> First, the spec shows that the pending bitmap is allocated _per CPU_, so
> we have to model this here appropriately.
> Second, you could have an LPI pending on one distributor, then change
> the associated collection to another distributor and trigger that
> interrupt again. This would make it pending on two VCPUs.
> Admittedly not the most prominent use case, but possible.

The exact scenario is related to the MOVI command, which changes the
affinity of the interrupt and also move any pending state from another
CPU. There is no guarantee that these two actions are completed
atomically w.r.t the delivery of interrupts to CPUs.

We *could* make it atomic, but that would be quite heavy handed.

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

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

* Re: [PATCH 09/13] KVM: arm64: handle pending bit for LPIs in ITS emulation
@ 2015-06-11 16:01         ` Marc Zyngier
  0 siblings, 0 replies; 104+ messages in thread
From: Marc Zyngier @ 2015-06-11 16:01 UTC (permalink / raw)
  To: Andre Przywara, Eric Auger
  Cc: christoffer.dall@linaro.org, kvmarm@lists.cs.columbia.edu,
	linux-arm-kernel@lists.infradead.org, kvm@vger.kernel.org

On 11/06/15 16:46, Andre Przywara wrote:
> Salut Eric,
> 
> On 06/09/2015 04:59 PM, Eric Auger wrote:
>> On 05/29/2015 11:53 AM, 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     | 66 +++++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/its-emul.h     |  3 ++
>>>  virt/kvm/arm/vgic-v3-emul.c |  2 ++
>>>  virt/kvm/arm/vgic.c         | 68 +++++++++++++++++++++++++++++++++------------
>>>  5 files changed, 124 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>> index fa17df6..de19c34 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 f0f4a9c..f75fb9e 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;
>> allocated in later patch. does not ease the review of the life cycle but
>> I guess it is accepted/acceptable.
> 
> I tried to move some bits around a bit and ran into several issues, so I
> guess we have to live with that.
> 
>> Isn't it somehow redundant to have a bitmap here where the collection
>> already indicates the target cpu id on which the LPI is pending?
> 
> Unfortunately only "somewhat", as Marc taught me the other day ;-)
> First, the spec shows that the pending bitmap is allocated _per CPU_, so
> we have to model this here appropriately.
> Second, you could have an LPI pending on one distributor, then change
> the associated collection to another distributor and trigger that
> interrupt again. This would make it pending on two VCPUs.
> Admittedly not the most prominent use case, but possible.

The exact scenario is related to the MOVI command, which changes the
affinity of the interrupt and also move any pending state from another
CPU. There is no guarantee that these two actions are completed
atomically w.r.t the delivery of interrupts to CPUs.

We *could* make it atomic, but that would be quite heavy handed.

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

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

* [PATCH 12/13] KVM: arm64: implement MSI injection in ITS emulation
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-11 17:43     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-11 17:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Andre,
On 05/29/2015 11:53 AM, 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 receivce
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).
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h      |  1 +
>  virt/kvm/arm/its-emul.c     | 49 +++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h     |  2 ++
>  virt/kvm/arm/vgic-v3-emul.c |  1 +
>  4 files changed, 53 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index de19c34..6bb138d 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 574cf05..35e886c 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -340,6 +340,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);
so now the internal state is different from the pending state in ext
memory. I don't really understand where the ext mem is used?
> +	inject = itte->enabled;
> +
> +out_unlock:
> +	spin_unlock(&its->lock);
> +
> +	if (inject) {
> +		spin_lock(&dist->lock);
> +		set_bit(cpuid, dist->irq_pending_on_cpu);
isn't it atomic op?

Best Regards

Eric
> +		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.
> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
> index 6152d04..cac1406 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -33,6 +33,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 66640c2fa..4513551 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -901,6 +901,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] 104+ messages in thread

* Re: [PATCH 12/13] KVM: arm64: implement MSI injection in ITS emulation
@ 2015-06-11 17:43     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-11 17:43 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

Hello Andre,
On 05/29/2015 11:53 AM, 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 receivce
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).
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h      |  1 +
>  virt/kvm/arm/its-emul.c     | 49 +++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h     |  2 ++
>  virt/kvm/arm/vgic-v3-emul.c |  1 +
>  4 files changed, 53 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index de19c34..6bb138d 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 574cf05..35e886c 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -340,6 +340,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);
so now the internal state is different from the pending state in ext
memory. I don't really understand where the ext mem is used?
> +	inject = itte->enabled;
> +
> +out_unlock:
> +	spin_unlock(&its->lock);
> +
> +	if (inject) {
> +		spin_lock(&dist->lock);
> +		set_bit(cpuid, dist->irq_pending_on_cpu);
isn't it atomic op?

Best Regards

Eric
> +		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.
> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
> index 6152d04..cac1406 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -33,6 +33,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 66640c2fa..4513551 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -901,6 +901,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] 104+ messages in thread

* [PATCH 10/13] KVM: arm64: sync LPI properties and status between guest and KVM
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-11 17:44     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-11 17:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/29/2015 11:53 AM, Andre Przywara wrote:
> The properties and status of the GICv3 LPIs are hold 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 property and status table in the kernel.
configuration and pending tables?
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/its-emul.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 140 insertions(+)
> 
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index f75fb9e..afd440e 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,7 +71,140 @@ 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_property(struct kvm *kvm, struct its_itte *itte, u8 prop)
inline?
> +{
> +	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 */
in 4kB chunks? you can merge that comment with the one below I think
> +#define CHUNK_SIZE 4096U
> +
>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
> +#define PROPBASE_TSIZE(x) (1U << (x & 0x1f))
> +
> +/*
> + * Scan the whole LPI property table and put the LPI configuration
it is called configuration table in archi spec.
> + * data in our own data structures. This relies on the LPI being
> + * mapped before.
> + * We scan from two sides:
> + * 1) for each byte in the table we care for the ones being enabled
> + * 2) for each mapped LPI we look into the table to spot LPIs being disabled
> + * Must be called with the ITS lock held.
> + */
> +static bool its_update_lpi_properties(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	u8 *prop;
> +	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 = PROPBASE_TSIZE(dist->propbaser);
according to the spec the IDbits should be compared against
GICD_TYPER.IDbits and treated accordingly?
> +
> +	prop = kmalloc(CHUNK_SIZE, GFP_KERNEL);
> +	if (!prop)
> +		return false;
> +
> +	while (tsize > 0) {
> +		int chunksize = min(tsize, CHUNK_SIZE);
> +
> +		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
> +		if (ret) {
> +			kfree(prop);
> +			break;
> +		}
although benign, double kfree and we return true; is it what we want?
> +
> +		/*
> +		 * 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) {
> +			/*
> +			 * Is the LPI covered by that part of the table we
> +			 * are currently looking at?
> +			 */
not sure this comment is needed, although I like comments :-)
> +			if (itte->lpi < lpi)
> +				continue;
> +			if (itte->lpi >= lpi + chunksize)
> +				continue;
could be combined
> +
> +			update_lpi_property(kvm, itte,
> +					    prop[itte->lpi - lpi]);
> +		}
> +		tsize -= chunksize;
> +		lpi += chunksize;
> +		propbase += chunksize;
> +	}
> +
> +	kfree(prop);
> +	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.
> + * Must be called with the ITS lock held.
> + */
> +static bool its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +	unsigned long *pendmask;
> +	u32 nr_lpis;
> +	gpa_t pendbase;
> +	int lpi = GIC_LPI_OFFSET;
> +	struct its_itte *itte;
> +	struct its_device *device;
> +	int ret;
> +	int lpi_bit, nr_bits;
> +
> +	pendbase = BASER_BASE_ADDRESS(dist->pendbaser[vcpu->vcpu_id]);
archi spec says the first 1kB of the table corresponds to other classes
of IRQs. where is this offset applied?
> +	nr_lpis = GIC_LPI_OFFSET;
> +
> +	pendmask = kmalloc(CHUNK_SIZE, GFP_KERNEL);
> +	if (!pendmask)
> +		return false;
> +
> +	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)
> +			break;
return false?


> +
> +		for_each_lpi(device, itte, vcpu->kvm) {
> +			lpi_bit = itte->lpi - lpi;
> +			if (lpi_bit < 0)
> +				continue;
> +			if (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);
> +		}
> +		nr_lpis -= nr_bits;
> +		lpi += nr_bits;
> +		pendbase += nr_bits / 8;
> +	}
> +
> +	kfree(pendmask);
> +	return true;
> +}
>  
>  /* distributor lock is hold by the VGIC MMIO handler */
>  static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
> @@ -350,6 +484,12 @@ static const struct vgic_io_range vgicv3_its_ranges[] = {
>  
>  void vgic_enable_lpis(struct kvm_vcpu *vcpu)
>  {
> +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> +
> +	spin_lock(&its->lock);
> +	its_update_lpi_properties(vcpu->kvm);
> +	its_sync_lpi_pending_table(vcpu);
question of the flush ...

Cheers

Eric
> +	spin_unlock(&its->lock);
>  }
>  
>  int vits_init(struct kvm *kvm)
> 

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

* Re: [PATCH 10/13] KVM: arm64: sync LPI properties and status between guest and KVM
@ 2015-06-11 17:44     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-11 17:44 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

On 05/29/2015 11:53 AM, Andre Przywara wrote:
> The properties and status of the GICv3 LPIs are hold 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 property and status table in the kernel.
configuration and pending tables?
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/its-emul.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 140 insertions(+)
> 
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index f75fb9e..afd440e 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,7 +71,140 @@ 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_property(struct kvm *kvm, struct its_itte *itte, u8 prop)
inline?
> +{
> +	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 */
in 4kB chunks? you can merge that comment with the one below I think
> +#define CHUNK_SIZE 4096U
> +
>  #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
> +#define PROPBASE_TSIZE(x) (1U << (x & 0x1f))
> +
> +/*
> + * Scan the whole LPI property table and put the LPI configuration
it is called configuration table in archi spec.
> + * data in our own data structures. This relies on the LPI being
> + * mapped before.
> + * We scan from two sides:
> + * 1) for each byte in the table we care for the ones being enabled
> + * 2) for each mapped LPI we look into the table to spot LPIs being disabled
> + * Must be called with the ITS lock held.
> + */
> +static bool its_update_lpi_properties(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	u8 *prop;
> +	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 = PROPBASE_TSIZE(dist->propbaser);
according to the spec the IDbits should be compared against
GICD_TYPER.IDbits and treated accordingly?
> +
> +	prop = kmalloc(CHUNK_SIZE, GFP_KERNEL);
> +	if (!prop)
> +		return false;
> +
> +	while (tsize > 0) {
> +		int chunksize = min(tsize, CHUNK_SIZE);
> +
> +		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
> +		if (ret) {
> +			kfree(prop);
> +			break;
> +		}
although benign, double kfree and we return true; is it what we want?
> +
> +		/*
> +		 * 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) {
> +			/*
> +			 * Is the LPI covered by that part of the table we
> +			 * are currently looking at?
> +			 */
not sure this comment is needed, although I like comments :-)
> +			if (itte->lpi < lpi)
> +				continue;
> +			if (itte->lpi >= lpi + chunksize)
> +				continue;
could be combined
> +
> +			update_lpi_property(kvm, itte,
> +					    prop[itte->lpi - lpi]);
> +		}
> +		tsize -= chunksize;
> +		lpi += chunksize;
> +		propbase += chunksize;
> +	}
> +
> +	kfree(prop);
> +	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.
> + * Must be called with the ITS lock held.
> + */
> +static bool its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +	unsigned long *pendmask;
> +	u32 nr_lpis;
> +	gpa_t pendbase;
> +	int lpi = GIC_LPI_OFFSET;
> +	struct its_itte *itte;
> +	struct its_device *device;
> +	int ret;
> +	int lpi_bit, nr_bits;
> +
> +	pendbase = BASER_BASE_ADDRESS(dist->pendbaser[vcpu->vcpu_id]);
archi spec says the first 1kB of the table corresponds to other classes
of IRQs. where is this offset applied?
> +	nr_lpis = GIC_LPI_OFFSET;
> +
> +	pendmask = kmalloc(CHUNK_SIZE, GFP_KERNEL);
> +	if (!pendmask)
> +		return false;
> +
> +	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)
> +			break;
return false?


> +
> +		for_each_lpi(device, itte, vcpu->kvm) {
> +			lpi_bit = itte->lpi - lpi;
> +			if (lpi_bit < 0)
> +				continue;
> +			if (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);
> +		}
> +		nr_lpis -= nr_bits;
> +		lpi += nr_bits;
> +		pendbase += nr_bits / 8;
> +	}
> +
> +	kfree(pendmask);
> +	return true;
> +}
>  
>  /* distributor lock is hold by the VGIC MMIO handler */
>  static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
> @@ -350,6 +484,12 @@ static const struct vgic_io_range vgicv3_its_ranges[] = {
>  
>  void vgic_enable_lpis(struct kvm_vcpu *vcpu)
>  {
> +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> +
> +	spin_lock(&its->lock);
> +	its_update_lpi_properties(vcpu->kvm);
> +	its_sync_lpi_pending_table(vcpu);
question of the flush ...

Cheers

Eric
> +	spin_unlock(&its->lock);
>  }
>  
>  int vits_init(struct kvm *kvm)
> 

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

* [PATCH 09/13] KVM: arm64: handle pending bit for LPIs in ITS emulation
  2015-06-11 16:01         ` Marc Zyngier
@ 2015-06-11 18:24           ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-11 18:24 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/11/2015 06:01 PM, Marc Zyngier wrote:
> On 11/06/15 16:46, Andre Przywara wrote:
>> Salut Eric,
>>
>> On 06/09/2015 04:59 PM, Eric Auger wrote:
>>> On 05/29/2015 11:53 AM, 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     | 66 +++++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/its-emul.h     |  3 ++
>>>>  virt/kvm/arm/vgic-v3-emul.c |  2 ++
>>>>  virt/kvm/arm/vgic.c         | 68 +++++++++++++++++++++++++++++++++------------
>>>>  5 files changed, 124 insertions(+), 17 deletions(-)
>>>>
>>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>>> index fa17df6..de19c34 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 f0f4a9c..f75fb9e 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;
>>> allocated in later patch. does not ease the review of the life cycle but
>>> I guess it is accepted/acceptable.
>>
>> I tried to move some bits around a bit and ran into several issues, so I
>> guess we have to live with that.
>>
>>> Isn't it somehow redundant to have a bitmap here where the collection
>>> already indicates the target cpu id on which the LPI is pending?
>>
>> Unfortunately only "somewhat", as Marc taught me the other day ;-)
>> First, the spec shows that the pending bitmap is allocated _per CPU_, so
>> we have to model this here appropriately.
>> Second, you could have an LPI pending on one distributor, then change
>> the associated collection to another distributor and trigger that
>> interrupt again. This would make it pending on two VCPUs.
>> Admittedly not the most prominent use case, but possible.
> 
> The exact scenario is related to the MOVI command, which changes the
> affinity of the interrupt and also move any pending state from another
> CPU. There is no guarantee that these two actions are completed
> atomically w.r.t the delivery of interrupts to CPUs.
> 
> We *could* make it atomic, but that would be quite heavy handed.

OK thanks,

The ITS command chapter is my next one ;-)

Best Regards

Eric
> 
> 	M.
> 

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

* Re: [PATCH 09/13] KVM: arm64: handle pending bit for LPIs in ITS emulation
@ 2015-06-11 18:24           ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-11 18:24 UTC (permalink / raw)
  To: Marc Zyngier, Andre Przywara
  Cc: christoffer.dall@linaro.org, kvmarm@lists.cs.columbia.edu,
	linux-arm-kernel@lists.infradead.org, kvm@vger.kernel.org

On 06/11/2015 06:01 PM, Marc Zyngier wrote:
> On 11/06/15 16:46, Andre Przywara wrote:
>> Salut Eric,
>>
>> On 06/09/2015 04:59 PM, Eric Auger wrote:
>>> On 05/29/2015 11:53 AM, 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     | 66 +++++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/its-emul.h     |  3 ++
>>>>  virt/kvm/arm/vgic-v3-emul.c |  2 ++
>>>>  virt/kvm/arm/vgic.c         | 68 +++++++++++++++++++++++++++++++++------------
>>>>  5 files changed, 124 insertions(+), 17 deletions(-)
>>>>
>>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>>> index fa17df6..de19c34 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 f0f4a9c..f75fb9e 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;
>>> allocated in later patch. does not ease the review of the life cycle but
>>> I guess it is accepted/acceptable.
>>
>> I tried to move some bits around a bit and ran into several issues, so I
>> guess we have to live with that.
>>
>>> Isn't it somehow redundant to have a bitmap here where the collection
>>> already indicates the target cpu id on which the LPI is pending?
>>
>> Unfortunately only "somewhat", as Marc taught me the other day ;-)
>> First, the spec shows that the pending bitmap is allocated _per CPU_, so
>> we have to model this here appropriately.
>> Second, you could have an LPI pending on one distributor, then change
>> the associated collection to another distributor and trigger that
>> interrupt again. This would make it pending on two VCPUs.
>> Admittedly not the most prominent use case, but possible.
> 
> The exact scenario is related to the MOVI command, which changes the
> affinity of the interrupt and also move any pending state from another
> CPU. There is no guarantee that these two actions are completed
> atomically w.r.t the delivery of interrupts to CPUs.
> 
> We *could* make it atomic, but that would be quite heavy handed.

OK thanks,

The ITS command chapter is my next one ;-)

Best Regards

Eric
> 
> 	M.
> 


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

* [PATCH 11/13] KVM: arm64: implement ITS command queue command handlers
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-12 15:28     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-12 15:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andre
On 05/29/2015 11:53 AM, 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 to let the ITS implementation use their own format.
, implement
> Implement handlers for the various ITS commands and let them store
> the requested relation into our own data structures.
> 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).
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/linux/irqchip/arm-gic-v3.h |   1 +
>  virt/kvm/arm/its-emul.c            | 422 ++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/its-emul.h            |  11 +
>  3 files changed, 433 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 0b450c7..651aacc 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -254,6 +254,7 @@
>  #define GITS_CMD_MAPD			0x08
>  #define GITS_CMD_MAPC			0x09
>  #define GITS_CMD_MAPVI			0x0a
> +#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 afd440e..574cf05 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)
>  
> @@ -345,9 +387,386 @@ 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)
> +
> +/*
> + * Handles the DISCARD command, which frees an ITTE.
> + * Must be called with the ITS lock held.
> + */
> +static int vits_cmd_handle_discard(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u32 device_id;
> +	u32 event_id;
> +	struct its_itte *itte;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte || !itte->collection)
> +		return E_ITS_DISCARD_UNMAPPED_INTERRUPT;
> +
> +	clear_bit(itte->collection->target_addr, itte->pending);
> +
> +	list_del(&itte->itte_list);
> +	kfree(itte);
> +	return 0;
> +}
> +
> +/*
> + * Handles the MOVI command, which moves an ITTE to a different collection.
> + * Must be called with the ITS lock held.
> + */
> +static int vits_cmd_handle_movi(struct kvm *kvm, u64 *its_cmd)
> +{
> +	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;
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_MOVI_UNMAPPED_INTERRUPT;
> +	if (!itte->collection)
> +		return E_ITS_MOVI_UNMAPPED_COLLECTION;
> +
> +	collection = find_collection(kvm, coll_id);
> +	if (!collection)
> +		return E_ITS_MOVI_UNMAPPED_COLLECTION;
> +
> +	if (test_and_clear_bit(itte->collection->target_addr, itte->pending))
> +		set_bit(collection->target_addr, itte->pending);
> +
> +	itte->collection = collection;
> +
> +	return 0;
> +}
> +
> +static struct its_collection *vits_new_collection(struct kvm *kvm, u32 coll_id)
> +{
> +	struct its_collection *collection;
> +
> +	collection = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
> +	if (!collection)
> +		return NULL;
> +	collection->collection_id = coll_id;
> +
> +	list_add_tail(&collection->coll_list,
> +		&kvm->arch.vgic.its.collection_list);
> +
> +	return collection;
> +}
> +
> +/*
> + * Handles the MAPVI and MAPI command, which maps LPIs to ITTEs.
> + * Must be called with the ITS lock held.
> + */
> +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;
> +	struct its_device *device;
> +	struct its_collection *collection, *new_coll = NULL;
> +	int lpi_nr;
> +
> +	device = find_its_device(kvm, device_id);
> +	if (!device)
> +		return E_ITS_MAPVI_UNMAPPED_DEVICE;
> +
> +	collection = find_collection(kvm, coll_id);
> +	if (!collection) {
> +		new_coll = vits_new_collection(kvm, coll_id);
> +		if (!new_coll)
> +			return -ENOMEM;
> +	}
> +
> +	if (cmd == GITS_CMD_MAPVI)
> +		lpi_nr = its_cmd_get_physical_id(its_cmd);
> +	else
> +		lpi_nr = event_id;
> +	if (lpi_nr < GIC_LPI_OFFSET ||
> +	    lpi_nr >= PROPBASE_TSIZE(dist->propbaser))
> +		return E_ITS_MAPVI_PHYSICALID_OOR;
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte) {
> +		/* Allocate a new ITTE */
> +		itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
> +		if (!itte) {
> +			kfree(new_coll);
> +			return -ENOMEM;
> +		}
> +		itte->pending = kcalloc(BITS_TO_LONGS(dist->nr_cpus),
> +					sizeof(long), GFP_KERNEL);
> +		if (!itte->pending) {
> +			kfree(itte);
> +			kfree(new_coll);
> +			return -ENOMEM;
> +		}
> +
> +		itte->event_id	= event_id;
> +
> +		list_add_tail(&itte->itte_list, &device->itt);
> +	}
> +
> +	itte->collection = collection ? collection : new_coll;
> +	itte->lpi = lpi_nr;
> +
> +	return 0;
> +}
> +
> +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);
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_mapd(struct kvm *kvm, u64 *its_cmd)
> +{
> +	bool valid = its_cmd_get_validbit(its_cmd);
> +	u32 device_id = its_cmd_get_deviceid(its_cmd);
> +	struct its_device *device;
> +
> +	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)
> +		return 0;
> +
> +	device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
> +	if (!device)
> +		return -ENOMEM;
> +
> +	device->device_id = device_id;
> +	INIT_LIST_HEAD(&device->itt);
> +
> +	list_add_tail(&device->dev_list,
> +		      &kvm->arch.vgic.its.device_list);
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_mapc(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u16 coll_id;
> +	u32 target_addr;
> +	struct its_collection *collection;
> +	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;
> +
> +	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)
> +			return 0;
> +
> +		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);
> +		return 0;
> +	}
> +
> +	if (!collection) {
> +		collection = vits_new_collection(kvm, coll_id);
> +		if (!collection)
> +			return -ENOMEM;
> +	}
> +
> +	collection->target_addr = target_addr;
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_clear(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u32 device_id;
> +	u32 event_id;
> +	struct its_itte *itte;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_CLEAR_UNMAPPED_INTERRUPT;
> +
> +	if (itte->collection)
> +		clear_bit(itte->collection->target_addr, itte->pending);
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +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;
> +	gpa_t propbase;
> +	int ret;
> +	u8 prop;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_INV_UNMAPPED_INTERRUPT;
> +
> +	propbase = BASER_BASE_ADDRESS(dist->propbaser);
> +	ret = kvm_read_guest(kvm, propbase + itte->lpi - GIC_LPI_OFFSET,
> +			     &prop, 1);
> +	if (ret)
> +		return ret;
> +
> +	update_lpi_property(kvm, itte, prop);
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +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_lpi_properties(kvm);
> +	its_sync_lpi_pending_table(vcpu);
is it requested to sync the pending state. archi spec seems to only talk
about config table?
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
> +{
> +	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;
> +
> +	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);
> +	}
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
>  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_MAPVI:
> +		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);
Don't you implement cmd = 0x3 as well, ie. set pending
> +		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 those commands: we are in sync all of the time */
> +		break;
so do you want to return an error in that case?
> +	}
> +
> +	return ret;
>  }
>  
>  static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
> @@ -532,6 +951,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);
shouldn't be here I think

Best Regards

Eric
>  			kfree(itte);
>  		}
>  		list_del(dev_cur);
> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
> index cc5d5ff..6152d04 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -36,4 +36,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_MAPVI_UNMAPPED_DEVICE		0x010a04
> +#define E_ITS_MAPVI_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] 104+ messages in thread

* Re: [PATCH 11/13] KVM: arm64: implement ITS command queue command handlers
@ 2015-06-12 15:28     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-12 15:28 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

Hi Andre
On 05/29/2015 11:53 AM, 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 to let the ITS implementation use their own format.
, implement
> Implement handlers for the various ITS commands and let them store
> the requested relation into our own data structures.
> 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).
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/linux/irqchip/arm-gic-v3.h |   1 +
>  virt/kvm/arm/its-emul.c            | 422 ++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/its-emul.h            |  11 +
>  3 files changed, 433 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 0b450c7..651aacc 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -254,6 +254,7 @@
>  #define GITS_CMD_MAPD			0x08
>  #define GITS_CMD_MAPC			0x09
>  #define GITS_CMD_MAPVI			0x0a
> +#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 afd440e..574cf05 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)
>  
> @@ -345,9 +387,386 @@ 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)
> +
> +/*
> + * Handles the DISCARD command, which frees an ITTE.
> + * Must be called with the ITS lock held.
> + */
> +static int vits_cmd_handle_discard(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u32 device_id;
> +	u32 event_id;
> +	struct its_itte *itte;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte || !itte->collection)
> +		return E_ITS_DISCARD_UNMAPPED_INTERRUPT;
> +
> +	clear_bit(itte->collection->target_addr, itte->pending);
> +
> +	list_del(&itte->itte_list);
> +	kfree(itte);
> +	return 0;
> +}
> +
> +/*
> + * Handles the MOVI command, which moves an ITTE to a different collection.
> + * Must be called with the ITS lock held.
> + */
> +static int vits_cmd_handle_movi(struct kvm *kvm, u64 *its_cmd)
> +{
> +	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;
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_MOVI_UNMAPPED_INTERRUPT;
> +	if (!itte->collection)
> +		return E_ITS_MOVI_UNMAPPED_COLLECTION;
> +
> +	collection = find_collection(kvm, coll_id);
> +	if (!collection)
> +		return E_ITS_MOVI_UNMAPPED_COLLECTION;
> +
> +	if (test_and_clear_bit(itte->collection->target_addr, itte->pending))
> +		set_bit(collection->target_addr, itte->pending);
> +
> +	itte->collection = collection;
> +
> +	return 0;
> +}
> +
> +static struct its_collection *vits_new_collection(struct kvm *kvm, u32 coll_id)
> +{
> +	struct its_collection *collection;
> +
> +	collection = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
> +	if (!collection)
> +		return NULL;
> +	collection->collection_id = coll_id;
> +
> +	list_add_tail(&collection->coll_list,
> +		&kvm->arch.vgic.its.collection_list);
> +
> +	return collection;
> +}
> +
> +/*
> + * Handles the MAPVI and MAPI command, which maps LPIs to ITTEs.
> + * Must be called with the ITS lock held.
> + */
> +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;
> +	struct its_device *device;
> +	struct its_collection *collection, *new_coll = NULL;
> +	int lpi_nr;
> +
> +	device = find_its_device(kvm, device_id);
> +	if (!device)
> +		return E_ITS_MAPVI_UNMAPPED_DEVICE;
> +
> +	collection = find_collection(kvm, coll_id);
> +	if (!collection) {
> +		new_coll = vits_new_collection(kvm, coll_id);
> +		if (!new_coll)
> +			return -ENOMEM;
> +	}
> +
> +	if (cmd == GITS_CMD_MAPVI)
> +		lpi_nr = its_cmd_get_physical_id(its_cmd);
> +	else
> +		lpi_nr = event_id;
> +	if (lpi_nr < GIC_LPI_OFFSET ||
> +	    lpi_nr >= PROPBASE_TSIZE(dist->propbaser))
> +		return E_ITS_MAPVI_PHYSICALID_OOR;
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte) {
> +		/* Allocate a new ITTE */
> +		itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
> +		if (!itte) {
> +			kfree(new_coll);
> +			return -ENOMEM;
> +		}
> +		itte->pending = kcalloc(BITS_TO_LONGS(dist->nr_cpus),
> +					sizeof(long), GFP_KERNEL);
> +		if (!itte->pending) {
> +			kfree(itte);
> +			kfree(new_coll);
> +			return -ENOMEM;
> +		}
> +
> +		itte->event_id	= event_id;
> +
> +		list_add_tail(&itte->itte_list, &device->itt);
> +	}
> +
> +	itte->collection = collection ? collection : new_coll;
> +	itte->lpi = lpi_nr;
> +
> +	return 0;
> +}
> +
> +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);
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_mapd(struct kvm *kvm, u64 *its_cmd)
> +{
> +	bool valid = its_cmd_get_validbit(its_cmd);
> +	u32 device_id = its_cmd_get_deviceid(its_cmd);
> +	struct its_device *device;
> +
> +	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)
> +		return 0;
> +
> +	device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
> +	if (!device)
> +		return -ENOMEM;
> +
> +	device->device_id = device_id;
> +	INIT_LIST_HEAD(&device->itt);
> +
> +	list_add_tail(&device->dev_list,
> +		      &kvm->arch.vgic.its.device_list);
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_mapc(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u16 coll_id;
> +	u32 target_addr;
> +	struct its_collection *collection;
> +	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;
> +
> +	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)
> +			return 0;
> +
> +		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);
> +		return 0;
> +	}
> +
> +	if (!collection) {
> +		collection = vits_new_collection(kvm, coll_id);
> +		if (!collection)
> +			return -ENOMEM;
> +	}
> +
> +	collection->target_addr = target_addr;
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_clear(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u32 device_id;
> +	u32 event_id;
> +	struct its_itte *itte;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_CLEAR_UNMAPPED_INTERRUPT;
> +
> +	if (itte->collection)
> +		clear_bit(itte->collection->target_addr, itte->pending);
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +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;
> +	gpa_t propbase;
> +	int ret;
> +	u8 prop;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_INV_UNMAPPED_INTERRUPT;
> +
> +	propbase = BASER_BASE_ADDRESS(dist->propbaser);
> +	ret = kvm_read_guest(kvm, propbase + itte->lpi - GIC_LPI_OFFSET,
> +			     &prop, 1);
> +	if (ret)
> +		return ret;
> +
> +	update_lpi_property(kvm, itte, prop);
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +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_lpi_properties(kvm);
> +	its_sync_lpi_pending_table(vcpu);
is it requested to sync the pending state. archi spec seems to only talk
about config table?
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
> +{
> +	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;
> +
> +	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);
> +	}
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
>  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_MAPVI:
> +		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);
Don't you implement cmd = 0x3 as well, ie. set pending
> +		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 those commands: we are in sync all of the time */
> +		break;
so do you want to return an error in that case?
> +	}
> +
> +	return ret;
>  }
>  
>  static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
> @@ -532,6 +951,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);
shouldn't be here I think

Best Regards

Eric
>  			kfree(itte);
>  		}
>  		list_del(dev_cur);
> diff --git a/virt/kvm/arm/its-emul.h b/virt/kvm/arm/its-emul.h
> index cc5d5ff..6152d04 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -36,4 +36,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_MAPVI_UNMAPPED_DEVICE		0x010a04
> +#define E_ITS_MAPVI_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] 104+ messages in thread

* [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-12 16:05     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-12 16:05 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/29/2015 11:53 AM, Andre Przywara wrote:
> 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.

in vgic-v3-emul.c you can now remove the old comments saying LPIs are
not supported, at the beginning of the file.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  Documentation/virtual/kvm/api.txt |  2 +-
>  arch/arm64/kvm/Kconfig            |  1 +
>  include/kvm/arm_vgic.h            | 10 ++++++++++
>  virt/kvm/arm/its-emul.c           |  9 ++++++++-
>  virt/kvm/arm/vgic-v3-emul.c       | 20 +++++++++++++++-----
>  virt/kvm/arm/vgic.c               | 10 ++++++++++
>  6 files changed, 45 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 891d64a..d20fd94 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2108,7 +2108,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 5105e29..6c432c0 100644
> --- a/arch/arm64/kvm/Kconfig
> +++ b/arch/arm64/kvm/Kconfig
> @@ -30,6 +30,7 @@ config KVM
>  	select SRCU
>  	select HAVE_KVM_EVENTFD
>  	select HAVE_KVM_IRQFD
> +	select HAVE_KVM_MSI
>  	---help---
>  	  Support hosting virtualized guest machines.
>  
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 6bb138d..8f1be6a 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;
> @@ -365,4 +366,13 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>  }
>  #endif
>  
> +#ifdef CONFIG_HAVE_KVM_MSI
> +int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
> +#else
> +static inline int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
> +{
> +	return -ENODEV;
> +}
> +#endif
> +
>  #endif
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index 35e886c..864de19 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -964,6 +964,7 @@ int vits_init(struct kvm *kvm)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
>  	struct vgic_its *its = &dist->its;
> +	int ret;
>  
>  	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
>  		return -ENXIO;
> @@ -977,9 +978,15 @@ 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;
>  
> -	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 4513551..71d0bcf 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -89,10 +89,11 @@ 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).
65536 LPIS
>   */
> -#define INTERRUPT_ID_BITS 10
> +#define INTERRUPT_ID_BITS_SPIS 10
> +#define INTERRUPT_ID_BITS_ITS 16
>  static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
>  			      struct kvm_exit_mmio *mmio, phys_addr_t offset)
>  {
> @@ -100,7 +101,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);
> @@ -519,7 +525,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 */
> +		dist->lpis_enabled = true;
> +		vgic_enable_lpis(vcpu);
> +		return true;
>  	}
>  	return false;
>  }
> @@ -546,6 +554,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 9f7b05f..09b1f46 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -2254,3 +2254,13 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
>  {
>  	return 0;
>  }
> +
> +#ifdef CONFIG_HAVE_KVM_MSI
> +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);
vits_inject_msi returns 0 on success while KVM API says KVM_SIGNAL_MSI
should return > 0 on delivery and 0 is guest blocked the MSI and -1 on error

Eric
> +	else
> +		return -ENODEV;
> +}
> +#endif
> 

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

* Re: [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
@ 2015-06-12 16:05     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-12 16:05 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

On 05/29/2015 11:53 AM, Andre Przywara wrote:
> 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.

in vgic-v3-emul.c you can now remove the old comments saying LPIs are
not supported, at the beginning of the file.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  Documentation/virtual/kvm/api.txt |  2 +-
>  arch/arm64/kvm/Kconfig            |  1 +
>  include/kvm/arm_vgic.h            | 10 ++++++++++
>  virt/kvm/arm/its-emul.c           |  9 ++++++++-
>  virt/kvm/arm/vgic-v3-emul.c       | 20 +++++++++++++++-----
>  virt/kvm/arm/vgic.c               | 10 ++++++++++
>  6 files changed, 45 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 891d64a..d20fd94 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2108,7 +2108,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 5105e29..6c432c0 100644
> --- a/arch/arm64/kvm/Kconfig
> +++ b/arch/arm64/kvm/Kconfig
> @@ -30,6 +30,7 @@ config KVM
>  	select SRCU
>  	select HAVE_KVM_EVENTFD
>  	select HAVE_KVM_IRQFD
> +	select HAVE_KVM_MSI
>  	---help---
>  	  Support hosting virtualized guest machines.
>  
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 6bb138d..8f1be6a 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;
> @@ -365,4 +366,13 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>  }
>  #endif
>  
> +#ifdef CONFIG_HAVE_KVM_MSI
> +int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
> +#else
> +static inline int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
> +{
> +	return -ENODEV;
> +}
> +#endif
> +
>  #endif
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index 35e886c..864de19 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -964,6 +964,7 @@ int vits_init(struct kvm *kvm)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
>  	struct vgic_its *its = &dist->its;
> +	int ret;
>  
>  	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
>  		return -ENXIO;
> @@ -977,9 +978,15 @@ 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;
>  
> -	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 4513551..71d0bcf 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -89,10 +89,11 @@ 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).
65536 LPIS
>   */
> -#define INTERRUPT_ID_BITS 10
> +#define INTERRUPT_ID_BITS_SPIS 10
> +#define INTERRUPT_ID_BITS_ITS 16
>  static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
>  			      struct kvm_exit_mmio *mmio, phys_addr_t offset)
>  {
> @@ -100,7 +101,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);
> @@ -519,7 +525,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 */
> +		dist->lpis_enabled = true;
> +		vgic_enable_lpis(vcpu);
> +		return true;
>  	}
>  	return false;
>  }
> @@ -546,6 +554,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 9f7b05f..09b1f46 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -2254,3 +2254,13 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
>  {
>  	return 0;
>  }
> +
> +#ifdef CONFIG_HAVE_KVM_MSI
> +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);
vits_inject_msi returns 0 on success while KVM API says KVM_SIGNAL_MSI
should return > 0 on delivery and 0 is guest blocked the MSI and -1 on error

Eric
> +	else
> +		return -ENODEV;
> +}
> +#endif
> 


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

* [PATCH 05/13] KVM: arm64: handle ITS related GICv3 redistributor registers
  2015-06-09  8:52     ` Eric Auger
@ 2015-06-12 17:03       ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-12 17:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

On 06/09/2015 09:52 AM, Eric Auger wrote:
> On 05/29/2015 11:53 AM, 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      |  4 ++++
>>  virt/kvm/arm/vgic-v3-emul.c | 43 +++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic.c         | 35 +++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic.h         |  4 ++++
>>  4 files changed, 86 insertions(+)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 37725bb..9ea0b3b 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -256,6 +256,10 @@ struct vgic_dist {
>>  	struct vgic_vm_ops	vm_ops;
>>  	struct vgic_io_device	dist_iodev;
>>  	struct vgic_io_device	*redist_iodevs;
>> +
> add some comments?
> /* LPI config table shared by all distributors */
>> +	u64			propbaser;
> /* LPI pending table per distributors */
>> +	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 16c6d8a..04f3aed 100644
>> --- a/virt/kvm/arm/vgic-v3-emul.c
>> +++ b/virt/kvm/arm/vgic-v3-emul.c
>> @@ -607,6 +607,37 @@ 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;
>> +
> you may add the same comment as below?
>> +	mode |= dist->lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
>> +	vgic_handle_base_register(vcpu, mmio, offset, &dist->propbaser, mode);
> having the PROPBASER programmed to different values on different redist
> with EnableLPIs==1 also is unpredictable. Do we plan to check that
> somewhere? Allow a single write?

Well, we are safe if the spec says it's unpredictable, aren't we?
I refrained from checking too many corner cases (same for the ITS
commands, btw), since we lack a good way of communicating errors.
SErrors into a guest do not work AFAIK, and spamming dmesg with
guest-triggerable messages is also bad.
After all this is an emulator, not a validator. So as long as this
doesn't affect the host and violates the spec, I think we get away with
ignoring stupid requests from the guest.
I am happy to revisit this shall the need arise.

>> +
>> +	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);
> pendbaser is not yet allocated. Wouldn't it make sense to introduce that
> patch later on?

I am quite glad having found a patch order which compiles ;-)
But well, I guess we have to address this as this strictly isn't safe if
pendbaser is NULL (though it works with how GCC compiles this).

Thanks for looking!

Cheers,
Andre.

> Eric
>> +
>> +	return false;
>> +}
>> +
>>  #define SGI_base(x) ((x) + SZ_64K)
>>  
>>  static const struct vgic_io_range vgic_redist_ranges[] = {
>> @@ -635,6 +666,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 2e9723aa..0a9236d 100644
>> --- a/virt/kvm/arm/vgic.c
>> +++ b/virt/kvm/arm/vgic.c
>> @@ -448,6 +448,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)
>>
> 

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

* Re: [PATCH 05/13] KVM: arm64: handle ITS related GICv3 redistributor registers
@ 2015-06-12 17:03       ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-12 17:03 UTC (permalink / raw)
  To: Eric Auger
  Cc: Marc Zyngier, kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu,
	linux-arm-kernel@lists.infradead.org

Hi Eric,

On 06/09/2015 09:52 AM, Eric Auger wrote:
> On 05/29/2015 11:53 AM, 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      |  4 ++++
>>  virt/kvm/arm/vgic-v3-emul.c | 43 +++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic.c         | 35 +++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic.h         |  4 ++++
>>  4 files changed, 86 insertions(+)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 37725bb..9ea0b3b 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -256,6 +256,10 @@ struct vgic_dist {
>>  	struct vgic_vm_ops	vm_ops;
>>  	struct vgic_io_device	dist_iodev;
>>  	struct vgic_io_device	*redist_iodevs;
>> +
> add some comments?
> /* LPI config table shared by all distributors */
>> +	u64			propbaser;
> /* LPI pending table per distributors */
>> +	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 16c6d8a..04f3aed 100644
>> --- a/virt/kvm/arm/vgic-v3-emul.c
>> +++ b/virt/kvm/arm/vgic-v3-emul.c
>> @@ -607,6 +607,37 @@ 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;
>> +
> you may add the same comment as below?
>> +	mode |= dist->lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE;
>> +	vgic_handle_base_register(vcpu, mmio, offset, &dist->propbaser, mode);
> having the PROPBASER programmed to different values on different redist
> with EnableLPIs==1 also is unpredictable. Do we plan to check that
> somewhere? Allow a single write?

Well, we are safe if the spec says it's unpredictable, aren't we?
I refrained from checking too many corner cases (same for the ITS
commands, btw), since we lack a good way of communicating errors.
SErrors into a guest do not work AFAIK, and spamming dmesg with
guest-triggerable messages is also bad.
After all this is an emulator, not a validator. So as long as this
doesn't affect the host and violates the spec, I think we get away with
ignoring stupid requests from the guest.
I am happy to revisit this shall the need arise.

>> +
>> +	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);
> pendbaser is not yet allocated. Wouldn't it make sense to introduce that
> patch later on?

I am quite glad having found a patch order which compiles ;-)
But well, I guess we have to address this as this strictly isn't safe if
pendbaser is NULL (though it works with how GCC compiles this).

Thanks for looking!

Cheers,
Andre.

> Eric
>> +
>> +	return false;
>> +}
>> +
>>  #define SGI_base(x) ((x) + SZ_64K)
>>  
>>  static const struct vgic_io_range vgic_redist_ranges[] = {
>> @@ -635,6 +666,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 2e9723aa..0a9236d 100644
>> --- a/virt/kvm/arm/vgic.c
>> +++ b/virt/kvm/arm/vgic.c
>> @@ -448,6 +448,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)
>>
> 

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

* Re: [PATCH 01/13] KVM: arm/arm64: VGIC: don't track used LRs in the distributor
  2015-05-29  9:53   ` Andre Przywara
  (?)
@ 2015-06-12 17:23   ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-12 17:23 UTC (permalink / raw)
  To: kvmarm

Hi Andre,
On 05/29/2015 11:53 AM, 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,
needs rewording
 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 78fb820..037b723 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -81,7 +81,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);
>  
> @@ -649,6 +648,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
> @@ -660,9 +670,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);
>  
can't we remove
			lr.state &= ~LR_STATE_PENDING;
			lr.state &= ~LR_STATE_ACTIVE;
			BUG_ON(lr.state & LR_STATE_MASK);
and simply replace by lr.state = 0


>  		/*
> @@ -705,7 +717,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. */
> @@ -1013,17 +1025,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);
> @@ -1064,18 +1065,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
> @@ -1087,23 +1076,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);
> @@ -1128,9 +1126,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... */
> @@ -1140,42 +1138,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 */
> -
hum. Why is it part of this patch? how do you justify that change
related to the state machine?
>  	if (vgic_queue_irq(vcpu, 0, irq)) {
>  		if (vgic_irq_is_edge(vcpu, irq)) {
>  			vgic_dist_irq_clear_pending(vcpu, irq);
> @@ -1348,29 +1324,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;
why removing level_. Reminds that maintenance IRQ are attached to level
sensitive IRQs?
> +	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);
don't get this
> +
> +		/*
> +		 * 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;
I am lost here. Aren't we looking at an empty LR? We have a
BUG_ON(!(vlr.state & LR_STATE_MASK)); above
>  
> -		vlr = vgic_get_lr(vcpu, lr);
> +		if (vlr.state & LR_STATE_PENDING)
> +			vgic_dist_irq_set_pending(vcpu, vlr.irq);
same
>  
> -		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);
Well overall I am too tired to understand the above changes but maybe
this is the right time to say "bon week end" to you ;-)

Overall impressed by the series nethertheless!

Best Regards

Eric
>  }
>  
> @@ -1592,11 +1583,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)
> @@ -1607,18 +1596,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] 104+ messages in thread

* [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-18  8:43     ` Eric Auger
  -1 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-18  8:43 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/29/2015 11:53 AM, Andre Przywara wrote:
> 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 +
>  include/kvm/arm_vgic.h            | 10 ++++++++++
>  virt/kvm/arm/its-emul.c           |  9 ++++++++-
>  virt/kvm/arm/vgic-v3-emul.c       | 20 +++++++++++++++-----
>  virt/kvm/arm/vgic.c               | 10 ++++++++++
>  6 files changed, 45 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 891d64a..d20fd94 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2108,7 +2108,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 5105e29..6c432c0 100644
> --- a/arch/arm64/kvm/Kconfig
> +++ b/arch/arm64/kvm/Kconfig
> @@ -30,6 +30,7 @@ config KVM
>  	select SRCU
>  	select HAVE_KVM_EVENTFD
>  	select HAVE_KVM_IRQFD
> +	select HAVE_KVM_MSI
>  	---help---
>  	  Support hosting virtualized guest machines.
>  
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 6bb138d..8f1be6a 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;
> @@ -365,4 +366,13 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>  }
>  #endif
>  
> +#ifdef CONFIG_HAVE_KVM_MSI
> +int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
> +#else
> +static inline int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
> +{
> +	return -ENODEV;
> +}
> +#endif
> +
>  #endif
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index 35e886c..864de19 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -964,6 +964,7 @@ int vits_init(struct kvm *kvm)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
>  	struct vgic_its *its = &dist->its;
> +	int ret;
>  
>  	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
>  		return -ENXIO;
> @@ -977,9 +978,15 @@ 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;
>  
> -	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 4513551..71d0bcf 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -89,10 +89,11 @@ 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
> +#define INTERRUPT_ID_BITS_ITS 16
>  static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
>  			      struct kvm_exit_mmio *mmio, phys_addr_t offset)
>  {
> @@ -100,7 +101,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);
> @@ -519,7 +525,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 */
> +		dist->lpis_enabled = true;
> +		vgic_enable_lpis(vcpu);
> +		return true;
>  	}
>  	return false;
>  }
> @@ -546,6 +554,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 9f7b05f..09b1f46 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -2254,3 +2254,13 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
>  {
>  	return 0;
>  }
> +
> +#ifdef CONFIG_HAVE_KVM_MSI
I don't think the if#def is requested since the entry is already
prevented in kvm_main.c in, case KVM_SIGNAL_MSI.

Eric
> +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;
> +}
> +#endif
> 

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

* Re: [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
@ 2015-06-18  8:43     ` Eric Auger
  0 siblings, 0 replies; 104+ messages in thread
From: Eric Auger @ 2015-06-18  8:43 UTC (permalink / raw)
  To: Andre Przywara, christoffer.dall, marc.zyngier
  Cc: kvmarm, linux-arm-kernel, kvm

On 05/29/2015 11:53 AM, Andre Przywara wrote:
> 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 +
>  include/kvm/arm_vgic.h            | 10 ++++++++++
>  virt/kvm/arm/its-emul.c           |  9 ++++++++-
>  virt/kvm/arm/vgic-v3-emul.c       | 20 +++++++++++++++-----
>  virt/kvm/arm/vgic.c               | 10 ++++++++++
>  6 files changed, 45 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 891d64a..d20fd94 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2108,7 +2108,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 5105e29..6c432c0 100644
> --- a/arch/arm64/kvm/Kconfig
> +++ b/arch/arm64/kvm/Kconfig
> @@ -30,6 +30,7 @@ config KVM
>  	select SRCU
>  	select HAVE_KVM_EVENTFD
>  	select HAVE_KVM_IRQFD
> +	select HAVE_KVM_MSI
>  	---help---
>  	  Support hosting virtualized guest machines.
>  
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 6bb138d..8f1be6a 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;
> @@ -365,4 +366,13 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>  }
>  #endif
>  
> +#ifdef CONFIG_HAVE_KVM_MSI
> +int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
> +#else
> +static inline int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
> +{
> +	return -ENODEV;
> +}
> +#endif
> +
>  #endif
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index 35e886c..864de19 100644
> --- a/virt/kvm/arm/its-emul.c
> +++ b/virt/kvm/arm/its-emul.c
> @@ -964,6 +964,7 @@ int vits_init(struct kvm *kvm)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
>  	struct vgic_its *its = &dist->its;
> +	int ret;
>  
>  	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
>  		return -ENXIO;
> @@ -977,9 +978,15 @@ 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;
>  
> -	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 4513551..71d0bcf 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -89,10 +89,11 @@ 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
> +#define INTERRUPT_ID_BITS_ITS 16
>  static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
>  			      struct kvm_exit_mmio *mmio, phys_addr_t offset)
>  {
> @@ -100,7 +101,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);
> @@ -519,7 +525,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 */
> +		dist->lpis_enabled = true;
> +		vgic_enable_lpis(vcpu);
> +		return true;
>  	}
>  	return false;
>  }
> @@ -546,6 +554,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 9f7b05f..09b1f46 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -2254,3 +2254,13 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
>  {
>  	return 0;
>  }
> +
> +#ifdef CONFIG_HAVE_KVM_MSI
I don't think the if#def is requested since the entry is already
prevented in kvm_main.c in, case KVM_SIGNAL_MSI.

Eric
> +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;
> +}
> +#endif
> 


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

* [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
  2015-06-18  8:43     ` Eric Auger
@ 2015-06-18 14:22       ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-18 14:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

On 06/18/2015 09:43 AM, Eric Auger wrote:
> On 05/29/2015 11:53 AM, Andre Przywara wrote:
>> 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>
>> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
>> index 9f7b05f..09b1f46 100644
>> --- a/virt/kvm/arm/vgic.c
>> +++ b/virt/kvm/arm/vgic.c
>> @@ -2254,3 +2254,13 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
>>  {
>>  	return 0;
>>  }
>> +
>> +#ifdef CONFIG_HAVE_KVM_MSI
> I don't think the if#def is requested since the entry is already
> prevented in kvm_main.c in, case KVM_SIGNAL_MSI.

But that fails compilation on ARM (which uses this file as well),
because we have a dummy fail function in the header if
CONFIG_HAVE_KVM_MSI is not defined.
So you get: error: redefinition of 'kvm_send_userspace_msi'

Cheers,
Andre.

>> +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;
>> +}
>> +#endif
>>
> 

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

* Re: [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
@ 2015-06-18 14:22       ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-18 14:22 UTC (permalink / raw)
  To: Eric Auger, christoffer.dall@linaro.org, Marc Zyngier
  Cc: kvmarm@lists.cs.columbia.edu,
	linux-arm-kernel@lists.infradead.org, kvm@vger.kernel.org

Hi Eric,

On 06/18/2015 09:43 AM, Eric Auger wrote:
> On 05/29/2015 11:53 AM, Andre Przywara wrote:
>> 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>
>> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
>> index 9f7b05f..09b1f46 100644
>> --- a/virt/kvm/arm/vgic.c
>> +++ b/virt/kvm/arm/vgic.c
>> @@ -2254,3 +2254,13 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
>>  {
>>  	return 0;
>>  }
>> +
>> +#ifdef CONFIG_HAVE_KVM_MSI
> I don't think the if#def is requested since the entry is already
> prevented in kvm_main.c in, case KVM_SIGNAL_MSI.

But that fails compilation on ARM (which uses this file as well),
because we have a dummy fail function in the header if
CONFIG_HAVE_KVM_MSI is not defined.
So you get: error: redefinition of 'kvm_send_userspace_msi'

Cheers,
Andre.

>> +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;
>> +}
>> +#endif
>>
> 

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

* [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
  2015-06-18 14:22       ` Andre Przywara
@ 2015-06-18 15:03         ` Pavel Fedin
  -1 siblings, 0 replies; 104+ messages in thread
From: Pavel Fedin @ 2015-06-18 15:03 UTC (permalink / raw)
  To: linux-arm-kernel

 Hello!

> But that fails compilation on ARM (which uses this file as well),
> because we have a dummy fail function in the header if
> CONFIG_HAVE_KVM_MSI is not defined.

 May be then remove that fail function too? Too many #ifdef's are not good...

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

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

* RE: [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
@ 2015-06-18 15:03         ` Pavel Fedin
  0 siblings, 0 replies; 104+ messages in thread
From: Pavel Fedin @ 2015-06-18 15:03 UTC (permalink / raw)
  To: 'Andre Przywara', 'Eric Auger', christoffer.dall,
	'Marc Zyngier'
  Cc: kvmarm, linux-arm-kernel, kvm

 Hello!

> But that fails compilation on ARM (which uses this file as well),
> because we have a dummy fail function in the header if
> CONFIG_HAVE_KVM_MSI is not defined.

 May be then remove that fail function too? Too many #ifdef's are not good...

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

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

* [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
  2015-06-18 15:03         ` Pavel Fedin
@ 2015-06-18 19:20           ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-18 19:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/18/2015 04:03 PM, Pavel Fedin wrote:
>  Hello!
> 
>> But that fails compilation on ARM (which uses this file as well),
>> because we have a dummy fail function in the header if
>> CONFIG_HAVE_KVM_MSI is not defined.
> 
>  May be then remove that fail function too? Too many #ifdef's are not good...

Yes, that seems to work - now. I think I had more code in there before
that prevented exposure without #ifdef guarding.

Cheers,
Andre.

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

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

* Re: [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller
@ 2015-06-18 19:20           ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-18 19:20 UTC (permalink / raw)
  To: Pavel Fedin, 'Eric Auger'
  Cc: Marc Zyngier, kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu,
	linux-arm-kernel@lists.infradead.org

On 06/18/2015 04:03 PM, Pavel Fedin wrote:
>  Hello!
> 
>> But that fails compilation on ARM (which uses this file as well),
>> because we have a dummy fail function in the header if
>> CONFIG_HAVE_KVM_MSI is not defined.
> 
>  May be then remove that fail function too? Too many #ifdef's are not good...

Yes, that seems to work - now. I think I had more code in there before
that prevented exposure without #ifdef guarding.

Cheers,
Andre.

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

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

* [PATCH 02/13] KVM: extend struct kvm_msi to hold a 32-bit device ID
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-28 19:12     ` Christoffer Dall
  -1 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-28 19:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 29, 2015 at 10:53:18AM +0100, Andre Przywara wrote:
> 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.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  Documentation/virtual/kvm/api.txt | 8 ++++++--
>  include/uapi/linux/kvm.h          | 4 +++-
>  2 files changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 9fa2bf8..891d64a 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2121,10 +2121,14 @@ 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 is valid, otherwise ignored.

I don't see what the 'otherwise ignored' part of the sentence here is
meant to say, that the flags field is otherwise ignored for other value?
That's not what the current API doc specifies, it specifies that the
remainder of the field must be 0.

> +devid: If KVM_MSI_VALID_DEVID is set, contains a value to identify the device
> +       that wrote the MSI message. For PCI, this is usually a BFD
> +       identifier in the lower 16 bits.

I assume plus something else that uniquely identifies the PCI
controller?

-Christoffer

>  
>  
>  4.71 KVM_CREATE_PIT2
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 4b60056..2a23705 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -965,12 +965,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	[flat|nested] 104+ messages in thread

* Re: [PATCH 02/13] KVM: extend struct kvm_msi to hold a 32-bit device ID
@ 2015-06-28 19:12     ` Christoffer Dall
  0 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-28 19:12 UTC (permalink / raw)
  To: Andre Przywara; +Cc: marc.zyngier, kvmarm, linux-arm-kernel, kvm

On Fri, May 29, 2015 at 10:53:18AM +0100, Andre Przywara wrote:
> 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.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  Documentation/virtual/kvm/api.txt | 8 ++++++--
>  include/uapi/linux/kvm.h          | 4 +++-
>  2 files changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 9fa2bf8..891d64a 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2121,10 +2121,14 @@ 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 is valid, otherwise ignored.

I don't see what the 'otherwise ignored' part of the sentence here is
meant to say, that the flags field is otherwise ignored for other value?
That's not what the current API doc specifies, it specifies that the
remainder of the field must be 0.

> +devid: If KVM_MSI_VALID_DEVID is set, contains a value to identify the device
> +       that wrote the MSI message. For PCI, this is usually a BFD
> +       identifier in the lower 16 bits.

I assume plus something else that uniquely identifies the PCI
controller?

-Christoffer

>  
>  
>  4.71 KVM_CREATE_PIT2
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 4b60056..2a23705 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -965,12 +965,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	[flat|nested] 104+ messages in thread

* [PATCH 03/13] KVM: arm/arm64: add emulation model specific destroy function
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-28 19:14     ` Christoffer Dall
  -1 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-28 19:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 29, 2015 at 10:53:19AM +0100, Andre Przywara wrote:
> Currently we destroy the VGIC emulation in one function that cares for
> all emulated models. The ITS emulation will require some
> differentiation, so introduce a per-emulation-model destroy method.

why do we need to differentiate between the destroy and the destroy
model?  This is not clear from the commit message.

-Christoffer

> Use it for a tiny GICv3 specific code already.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  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 e9c3a7a..fbfdd6f 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -818,6 +818,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)
>  {
> @@ -830,6 +838,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 037b723..6ea30e0 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -102,6 +102,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.
> @@ -1631,6 +1639,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);
>  
> @@ -1647,7 +1657,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	[flat|nested] 104+ messages in thread

* Re: [PATCH 03/13] KVM: arm/arm64: add emulation model specific destroy function
@ 2015-06-28 19:14     ` Christoffer Dall
  0 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-28 19:14 UTC (permalink / raw)
  To: Andre Przywara; +Cc: marc.zyngier, kvmarm, linux-arm-kernel, kvm

On Fri, May 29, 2015 at 10:53:19AM +0100, Andre Przywara wrote:
> Currently we destroy the VGIC emulation in one function that cares for
> all emulated models. The ITS emulation will require some
> differentiation, so introduce a per-emulation-model destroy method.

why do we need to differentiate between the destroy and the destroy
model?  This is not clear from the commit message.

-Christoffer

> Use it for a tiny GICv3 specific code already.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  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 e9c3a7a..fbfdd6f 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -818,6 +818,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)
>  {
> @@ -830,6 +838,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 037b723..6ea30e0 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -102,6 +102,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.
> @@ -1631,6 +1639,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);
>  
> @@ -1647,7 +1657,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	[flat|nested] 104+ messages in thread

* [PATCH 10/13] KVM: arm64: sync LPI properties and status between guest and KVM
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-28 19:33     ` Christoffer Dall
  -1 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-28 19:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 29, 2015 at 10:53:26AM +0100, Andre Przywara wrote:
> The properties and status of the GICv3 LPIs are hold 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 property and status table in the kernel.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/its-emul.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 140 insertions(+)
> 
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index f75fb9e..afd440e 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,7 +71,140 @@ 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_property(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)
> +#define PROPBASE_TSIZE(x) (1U << (x & 0x1f))
> +
> +/*
> + * Scan the whole LPI property table and put the LPI configuration
> + * data in our own data structures. This relies on the LPI being
> + * mapped before.
> + * We scan from two sides:
> + * 1) for each byte in the table we care for the ones being enabled
> + * 2) for each mapped LPI we look into the table to spot LPIs being disabled
> + * Must be called with the ITS lock held.
> + */
> +static bool its_update_lpi_properties(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	u8 *prop;
> +	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 = PROPBASE_TSIZE(dist->propbaser);
> +
> +	prop = kmalloc(CHUNK_SIZE, GFP_KERNEL);
> +	if (!prop)
> +		return false;
> +
> +	while (tsize > 0) {
> +		int chunksize = min(tsize, CHUNK_SIZE);
> +
> +		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
> +		if (ret) {
> +			kfree(prop);
> +			break;
> +		}
> +
> +		/*
> +		 * 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) {
> +			/*
> +			 * Is the LPI covered by that part of the table we
> +			 * are currently looking at?
> +			 */
> +			if (itte->lpi < lpi)
> +				continue;
> +			if (itte->lpi >= lpi + chunksize)
> +				continue;
> +
> +			update_lpi_property(kvm, itte,
> +					    prop[itte->lpi - lpi]);
> +		}
> +		tsize -= chunksize;
> +		lpi += chunksize;
> +		propbase += chunksize;
> +	}
> +
> +	kfree(prop);
> +	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.
> + * Must be called with the ITS lock held.
> + */
> +static bool its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +	unsigned long *pendmask;
> +	u32 nr_lpis;
> +	gpa_t pendbase;
> +	int lpi = GIC_LPI_OFFSET;
> +	struct its_itte *itte;
> +	struct its_device *device;
> +	int ret;
> +	int lpi_bit, nr_bits;
> +
> +	pendbase = BASER_BASE_ADDRESS(dist->pendbaser[vcpu->vcpu_id]);
> +	nr_lpis = GIC_LPI_OFFSET;
> +
> +	pendmask = kmalloc(CHUNK_SIZE, GFP_KERNEL);
> +	if (!pendmask)
> +		return false;
> +
> +	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)
> +			break;
> +
> +		for_each_lpi(device, itte, vcpu->kvm) {
> +			lpi_bit = itte->lpi - lpi;
> +			if (lpi_bit < 0)
> +				continue;
> +			if (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);
> +		}
> +		nr_lpis -= nr_bits;
> +		lpi += nr_bits;
> +		pendbase += nr_bits / 8;
> +	}
> +
> +	kfree(pendmask);
> +	return true;
> +}
>  
>  /* distributor lock is hold by the VGIC MMIO handler */
>  static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
> @@ -350,6 +484,12 @@ static const struct vgic_io_range vgicv3_its_ranges[] = {
>  
>  void vgic_enable_lpis(struct kvm_vcpu *vcpu)
>  {
> +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> +
> +	spin_lock(&its->lock);
> +	its_update_lpi_properties(vcpu->kvm);
> +	its_sync_lpi_pending_table(vcpu);

looks like you're doing a lot of kmalloc(, GFP_KERNEL) and
__copy_from_user while holding spinlocks here???

-Christoffer

> +	spin_unlock(&its->lock);
>  }
>  
>  int vits_init(struct kvm *kvm)
> -- 
> 2.3.5
> 

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

* Re: [PATCH 10/13] KVM: arm64: sync LPI properties and status between guest and KVM
@ 2015-06-28 19:33     ` Christoffer Dall
  0 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-28 19:33 UTC (permalink / raw)
  To: Andre Przywara; +Cc: marc.zyngier, kvmarm, linux-arm-kernel, kvm

On Fri, May 29, 2015 at 10:53:26AM +0100, Andre Przywara wrote:
> The properties and status of the GICv3 LPIs are hold 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 property and status table in the kernel.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/its-emul.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 140 insertions(+)
> 
> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
> index f75fb9e..afd440e 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,7 +71,140 @@ 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_property(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)
> +#define PROPBASE_TSIZE(x) (1U << (x & 0x1f))
> +
> +/*
> + * Scan the whole LPI property table and put the LPI configuration
> + * data in our own data structures. This relies on the LPI being
> + * mapped before.
> + * We scan from two sides:
> + * 1) for each byte in the table we care for the ones being enabled
> + * 2) for each mapped LPI we look into the table to spot LPIs being disabled
> + * Must be called with the ITS lock held.
> + */
> +static bool its_update_lpi_properties(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	u8 *prop;
> +	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 = PROPBASE_TSIZE(dist->propbaser);
> +
> +	prop = kmalloc(CHUNK_SIZE, GFP_KERNEL);
> +	if (!prop)
> +		return false;
> +
> +	while (tsize > 0) {
> +		int chunksize = min(tsize, CHUNK_SIZE);
> +
> +		ret = kvm_read_guest(kvm, propbase, prop, chunksize);
> +		if (ret) {
> +			kfree(prop);
> +			break;
> +		}
> +
> +		/*
> +		 * 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) {
> +			/*
> +			 * Is the LPI covered by that part of the table we
> +			 * are currently looking at?
> +			 */
> +			if (itte->lpi < lpi)
> +				continue;
> +			if (itte->lpi >= lpi + chunksize)
> +				continue;
> +
> +			update_lpi_property(kvm, itte,
> +					    prop[itte->lpi - lpi]);
> +		}
> +		tsize -= chunksize;
> +		lpi += chunksize;
> +		propbase += chunksize;
> +	}
> +
> +	kfree(prop);
> +	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.
> + * Must be called with the ITS lock held.
> + */
> +static bool its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +	unsigned long *pendmask;
> +	u32 nr_lpis;
> +	gpa_t pendbase;
> +	int lpi = GIC_LPI_OFFSET;
> +	struct its_itte *itte;
> +	struct its_device *device;
> +	int ret;
> +	int lpi_bit, nr_bits;
> +
> +	pendbase = BASER_BASE_ADDRESS(dist->pendbaser[vcpu->vcpu_id]);
> +	nr_lpis = GIC_LPI_OFFSET;
> +
> +	pendmask = kmalloc(CHUNK_SIZE, GFP_KERNEL);
> +	if (!pendmask)
> +		return false;
> +
> +	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)
> +			break;
> +
> +		for_each_lpi(device, itte, vcpu->kvm) {
> +			lpi_bit = itte->lpi - lpi;
> +			if (lpi_bit < 0)
> +				continue;
> +			if (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);
> +		}
> +		nr_lpis -= nr_bits;
> +		lpi += nr_bits;
> +		pendbase += nr_bits / 8;
> +	}
> +
> +	kfree(pendmask);
> +	return true;
> +}
>  
>  /* distributor lock is hold by the VGIC MMIO handler */
>  static bool handle_mmio_misc_gits(struct kvm_vcpu *vcpu,
> @@ -350,6 +484,12 @@ static const struct vgic_io_range vgicv3_its_ranges[] = {
>  
>  void vgic_enable_lpis(struct kvm_vcpu *vcpu)
>  {
> +	struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
> +
> +	spin_lock(&its->lock);
> +	its_update_lpi_properties(vcpu->kvm);
> +	its_sync_lpi_pending_table(vcpu);

looks like you're doing a lot of kmalloc(, GFP_KERNEL) and
__copy_from_user while holding spinlocks here???

-Christoffer

> +	spin_unlock(&its->lock);
>  }
>  
>  int vits_init(struct kvm *kvm)
> -- 
> 2.3.5
> 

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

* [PATCH 07/13] KVM: arm64: implement basic ITS register handlers
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-28 19:36     ` Christoffer Dall
  -1 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-28 19:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 29, 2015 at 10:53:23AM +0100, 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,CREAD,CWRITER}
>   those implement the ITS command buffer handling
> 
> 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            | 172 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h            |   1 +
>  virt/kvm/arm/vgic-v3-emul.c        |   2 +
>  5 files changed, 186 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index d76c2d9..3b8e3a1 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 7b283ce..82bc34a 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)
> +
> +/* distributor lock is hold 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,107 @@ 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);
> +	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);
> +}
> +
>  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;
> +	u64 cmd_buf[4];
> +	gpa_t cbaser = its_cmd_buffer_base(vcpu->kvm);
> +	u32 reg;
> +	int ret;
> +
> +	spin_lock(&its->lock);
> +	switch (offset & ~3) {
> +	case 0x00:
> +		reg = its->cwriter & 0xfffe0;
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
> +		reg &= 0xfffe0;
> +		if (reg > its_cmd_buffer_size(vcpu->kvm))
> +			break;
> +		while (its->creadr != reg) {
> +			ret = kvm_read_guest(vcpu->kvm, cbaser + its->creadr,
> +					     cmd_buf, 32);

some more potential sleeping while holding a spinlock here?

> +			if (ret)
> +				break;
> +			vits_handle_command(vcpu, cmd_buf);
> +			its->creadr += 32;
> +			if (its->creadr == its_cmd_buffer_size(vcpu->kvm))
> +				its->creadr = 0;
> +		}
> +		its->cwriter = reg;
> +		break;
> +	case 0x04:
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
> +		break;
> +	}
> +	spin_unlock(&its->lock);
>  	return false;
>  }
>  
> @@ -64,6 +203,22 @@ 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;
> +
> +	spin_lock(&its->lock);
> +	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;
> +	}
> +	spin_unlock(&its->lock);
>  	return false;
>  }
>  
> @@ -119,9 +274,26 @@ int vits_init(struct kvm *kvm)
>  	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
>  		return -ENXIO;
>  
> +	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 4e40684..fa81c4b 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -881,6 +881,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	[flat|nested] 104+ messages in thread

* Re: [PATCH 07/13] KVM: arm64: implement basic ITS register handlers
@ 2015-06-28 19:36     ` Christoffer Dall
  0 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-28 19:36 UTC (permalink / raw)
  To: Andre Przywara; +Cc: marc.zyngier, kvmarm, linux-arm-kernel, kvm

On Fri, May 29, 2015 at 10:53:23AM +0100, 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,CREAD,CWRITER}
>   those implement the ITS command buffer handling
> 
> 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            | 172 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/its-emul.h            |   1 +
>  virt/kvm/arm/vgic-v3-emul.c        |   2 +
>  5 files changed, 186 insertions(+)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index d76c2d9..3b8e3a1 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 7b283ce..82bc34a 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)
> +
> +/* distributor lock is hold 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,107 @@ 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);
> +	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);
> +}
> +
>  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;
> +	u64 cmd_buf[4];
> +	gpa_t cbaser = its_cmd_buffer_base(vcpu->kvm);
> +	u32 reg;
> +	int ret;
> +
> +	spin_lock(&its->lock);
> +	switch (offset & ~3) {
> +	case 0x00:
> +		reg = its->cwriter & 0xfffe0;
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
> +		reg &= 0xfffe0;
> +		if (reg > its_cmd_buffer_size(vcpu->kvm))
> +			break;
> +		while (its->creadr != reg) {
> +			ret = kvm_read_guest(vcpu->kvm, cbaser + its->creadr,
> +					     cmd_buf, 32);

some more potential sleeping while holding a spinlock here?

> +			if (ret)
> +				break;
> +			vits_handle_command(vcpu, cmd_buf);
> +			its->creadr += 32;
> +			if (its->creadr == its_cmd_buffer_size(vcpu->kvm))
> +				its->creadr = 0;
> +		}
> +		its->cwriter = reg;
> +		break;
> +	case 0x04:
> +		vgic_reg_access(mmio, &reg, offset & 3,
> +				ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
> +		break;
> +	}
> +	spin_unlock(&its->lock);
>  	return false;
>  }
>  
> @@ -64,6 +203,22 @@ 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;
> +
> +	spin_lock(&its->lock);
> +	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;
> +	}
> +	spin_unlock(&its->lock);
>  	return false;
>  }
>  
> @@ -119,9 +274,26 @@ int vits_init(struct kvm *kvm)
>  	if (IS_VGIC_ADDR_UNDEF(dist->vgic_its_base))
>  		return -ENXIO;
>  
> +	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 4e40684..fa81c4b 100644
> --- a/virt/kvm/arm/vgic-v3-emul.c
> +++ b/virt/kvm/arm/vgic-v3-emul.c
> @@ -881,6 +881,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	[flat|nested] 104+ messages in thread

* [PATCH 11/13] KVM: arm64: implement ITS command queue command handlers
  2015-05-29  9:53   ` Andre Przywara
@ 2015-06-28 19:41     ` Christoffer Dall
  -1 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-28 19:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 29, 2015 at 10:53:27AM +0100, 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 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.
> 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).
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/linux/irqchip/arm-gic-v3.h |   1 +
>  virt/kvm/arm/its-emul.c            | 422 ++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/its-emul.h            |  11 +
>  3 files changed, 433 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 0b450c7..651aacc 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -254,6 +254,7 @@
>  #define GITS_CMD_MAPD			0x08
>  #define GITS_CMD_MAPC			0x09
>  #define GITS_CMD_MAPVI			0x0a
> +#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 afd440e..574cf05 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)
>  
> @@ -345,9 +387,386 @@ 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)
> +
> +/*
> + * Handles the DISCARD command, which frees an ITTE.
> + * Must be called with the ITS lock held.
> + */
> +static int vits_cmd_handle_discard(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u32 device_id;
> +	u32 event_id;
> +	struct its_itte *itte;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte || !itte->collection)
> +		return E_ITS_DISCARD_UNMAPPED_INTERRUPT;
> +
> +	clear_bit(itte->collection->target_addr, itte->pending);
> +
> +	list_del(&itte->itte_list);
> +	kfree(itte);
> +	return 0;
> +}
> +
> +/*
> + * Handles the MOVI command, which moves an ITTE to a different collection.
> + * Must be called with the ITS lock held.
> + */
> +static int vits_cmd_handle_movi(struct kvm *kvm, u64 *its_cmd)
> +{
> +	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;
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_MOVI_UNMAPPED_INTERRUPT;
> +	if (!itte->collection)
> +		return E_ITS_MOVI_UNMAPPED_COLLECTION;
> +
> +	collection = find_collection(kvm, coll_id);
> +	if (!collection)
> +		return E_ITS_MOVI_UNMAPPED_COLLECTION;
> +
> +	if (test_and_clear_bit(itte->collection->target_addr, itte->pending))
> +		set_bit(collection->target_addr, itte->pending);
> +
> +	itte->collection = collection;
> +
> +	return 0;
> +}
> +
> +static struct its_collection *vits_new_collection(struct kvm *kvm, u32 coll_id)
> +{
> +	struct its_collection *collection;
> +
> +	collection = kmalloc(sizeof(struct its_collection), GFP_KERNEL);

If I manage to understand the structure here, you're calling all these
handler functions with a spinlock held so any operation that may sleep
could cause your system to deadlock.

I'll stop looking for these and recommend you go over the whole series
for these.

Perhaps the right thing to do is to synchronize access to your data
structure (why you hold the spinlock right?) with RCU if you can...

-Christoffer

> +	if (!collection)
> +		return NULL;
> +	collection->collection_id = coll_id;
> +
> +	list_add_tail(&collection->coll_list,
> +		&kvm->arch.vgic.its.collection_list);
> +
> +	return collection;
> +}
> +
> +/*
> + * Handles the MAPVI and MAPI command, which maps LPIs to ITTEs.
> + * Must be called with the ITS lock held.
> + */
> +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;
> +	struct its_device *device;
> +	struct its_collection *collection, *new_coll = NULL;
> +	int lpi_nr;
> +
> +	device = find_its_device(kvm, device_id);
> +	if (!device)
> +		return E_ITS_MAPVI_UNMAPPED_DEVICE;
> +
> +	collection = find_collection(kvm, coll_id);
> +	if (!collection) {
> +		new_coll = vits_new_collection(kvm, coll_id);
> +		if (!new_coll)
> +			return -ENOMEM;
> +	}
> +
> +	if (cmd == GITS_CMD_MAPVI)
> +		lpi_nr = its_cmd_get_physical_id(its_cmd);
> +	else
> +		lpi_nr = event_id;
> +	if (lpi_nr < GIC_LPI_OFFSET ||
> +	    lpi_nr >= PROPBASE_TSIZE(dist->propbaser))
> +		return E_ITS_MAPVI_PHYSICALID_OOR;
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte) {
> +		/* Allocate a new ITTE */
> +		itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
> +		if (!itte) {
> +			kfree(new_coll);
> +			return -ENOMEM;
> +		}
> +		itte->pending = kcalloc(BITS_TO_LONGS(dist->nr_cpus),
> +					sizeof(long), GFP_KERNEL);
> +		if (!itte->pending) {
> +			kfree(itte);
> +			kfree(new_coll);
> +			return -ENOMEM;
> +		}
> +
> +		itte->event_id	= event_id;
> +
> +		list_add_tail(&itte->itte_list, &device->itt);
> +	}
> +
> +	itte->collection = collection ? collection : new_coll;
> +	itte->lpi = lpi_nr;
> +
> +	return 0;
> +}
> +
> +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);
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_mapd(struct kvm *kvm, u64 *its_cmd)
> +{
> +	bool valid = its_cmd_get_validbit(its_cmd);
> +	u32 device_id = its_cmd_get_deviceid(its_cmd);
> +	struct its_device *device;
> +
> +	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)
> +		return 0;
> +
> +	device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
> +	if (!device)
> +		return -ENOMEM;
> +
> +	device->device_id = device_id;
> +	INIT_LIST_HEAD(&device->itt);
> +
> +	list_add_tail(&device->dev_list,
> +		      &kvm->arch.vgic.its.device_list);
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_mapc(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u16 coll_id;
> +	u32 target_addr;
> +	struct its_collection *collection;
> +	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;
> +
> +	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)
> +			return 0;
> +
> +		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);
> +		return 0;
> +	}
> +
> +	if (!collection) {
> +		collection = vits_new_collection(kvm, coll_id);
> +		if (!collection)
> +			return -ENOMEM;
> +	}
> +
> +	collection->target_addr = target_addr;
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_clear(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u32 device_id;
> +	u32 event_id;
> +	struct its_itte *itte;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_CLEAR_UNMAPPED_INTERRUPT;
> +
> +	if (itte->collection)
> +		clear_bit(itte->collection->target_addr, itte->pending);
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +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;
> +	gpa_t propbase;
> +	int ret;
> +	u8 prop;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_INV_UNMAPPED_INTERRUPT;
> +
> +	propbase = BASER_BASE_ADDRESS(dist->propbaser);
> +	ret = kvm_read_guest(kvm, propbase + itte->lpi - GIC_LPI_OFFSET,
> +			     &prop, 1);
> +	if (ret)
> +		return ret;
> +
> +	update_lpi_property(kvm, itte, prop);
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +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_lpi_properties(kvm);
> +	its_sync_lpi_pending_table(vcpu);
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
> +{
> +	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;
> +
> +	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);
> +	}
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
>  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_MAPVI:
> +		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 those commands: we are in sync all of the time */
> +		break;
> +	}
> +
> +	return ret;
>  }
>  
>  static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
> @@ -532,6 +951,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 cc5d5ff..6152d04 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -36,4 +36,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_MAPVI_UNMAPPED_DEVICE		0x010a04
> +#define E_ITS_MAPVI_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	[flat|nested] 104+ messages in thread

* Re: [PATCH 11/13] KVM: arm64: implement ITS command queue command handlers
@ 2015-06-28 19:41     ` Christoffer Dall
  0 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-28 19:41 UTC (permalink / raw)
  To: Andre Przywara; +Cc: marc.zyngier, kvmarm, linux-arm-kernel, kvm

On Fri, May 29, 2015 at 10:53:27AM +0100, 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 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.
> 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).
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/linux/irqchip/arm-gic-v3.h |   1 +
>  virt/kvm/arm/its-emul.c            | 422 ++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/its-emul.h            |  11 +
>  3 files changed, 433 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 0b450c7..651aacc 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -254,6 +254,7 @@
>  #define GITS_CMD_MAPD			0x08
>  #define GITS_CMD_MAPC			0x09
>  #define GITS_CMD_MAPVI			0x0a
> +#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 afd440e..574cf05 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)
>  
> @@ -345,9 +387,386 @@ 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)
> +
> +/*
> + * Handles the DISCARD command, which frees an ITTE.
> + * Must be called with the ITS lock held.
> + */
> +static int vits_cmd_handle_discard(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u32 device_id;
> +	u32 event_id;
> +	struct its_itte *itte;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte || !itte->collection)
> +		return E_ITS_DISCARD_UNMAPPED_INTERRUPT;
> +
> +	clear_bit(itte->collection->target_addr, itte->pending);
> +
> +	list_del(&itte->itte_list);
> +	kfree(itte);
> +	return 0;
> +}
> +
> +/*
> + * Handles the MOVI command, which moves an ITTE to a different collection.
> + * Must be called with the ITS lock held.
> + */
> +static int vits_cmd_handle_movi(struct kvm *kvm, u64 *its_cmd)
> +{
> +	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;
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_MOVI_UNMAPPED_INTERRUPT;
> +	if (!itte->collection)
> +		return E_ITS_MOVI_UNMAPPED_COLLECTION;
> +
> +	collection = find_collection(kvm, coll_id);
> +	if (!collection)
> +		return E_ITS_MOVI_UNMAPPED_COLLECTION;
> +
> +	if (test_and_clear_bit(itte->collection->target_addr, itte->pending))
> +		set_bit(collection->target_addr, itte->pending);
> +
> +	itte->collection = collection;
> +
> +	return 0;
> +}
> +
> +static struct its_collection *vits_new_collection(struct kvm *kvm, u32 coll_id)
> +{
> +	struct its_collection *collection;
> +
> +	collection = kmalloc(sizeof(struct its_collection), GFP_KERNEL);

If I manage to understand the structure here, you're calling all these
handler functions with a spinlock held so any operation that may sleep
could cause your system to deadlock.

I'll stop looking for these and recommend you go over the whole series
for these.

Perhaps the right thing to do is to synchronize access to your data
structure (why you hold the spinlock right?) with RCU if you can...

-Christoffer

> +	if (!collection)
> +		return NULL;
> +	collection->collection_id = coll_id;
> +
> +	list_add_tail(&collection->coll_list,
> +		&kvm->arch.vgic.its.collection_list);
> +
> +	return collection;
> +}
> +
> +/*
> + * Handles the MAPVI and MAPI command, which maps LPIs to ITTEs.
> + * Must be called with the ITS lock held.
> + */
> +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;
> +	struct its_device *device;
> +	struct its_collection *collection, *new_coll = NULL;
> +	int lpi_nr;
> +
> +	device = find_its_device(kvm, device_id);
> +	if (!device)
> +		return E_ITS_MAPVI_UNMAPPED_DEVICE;
> +
> +	collection = find_collection(kvm, coll_id);
> +	if (!collection) {
> +		new_coll = vits_new_collection(kvm, coll_id);
> +		if (!new_coll)
> +			return -ENOMEM;
> +	}
> +
> +	if (cmd == GITS_CMD_MAPVI)
> +		lpi_nr = its_cmd_get_physical_id(its_cmd);
> +	else
> +		lpi_nr = event_id;
> +	if (lpi_nr < GIC_LPI_OFFSET ||
> +	    lpi_nr >= PROPBASE_TSIZE(dist->propbaser))
> +		return E_ITS_MAPVI_PHYSICALID_OOR;
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte) {
> +		/* Allocate a new ITTE */
> +		itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
> +		if (!itte) {
> +			kfree(new_coll);
> +			return -ENOMEM;
> +		}
> +		itte->pending = kcalloc(BITS_TO_LONGS(dist->nr_cpus),
> +					sizeof(long), GFP_KERNEL);
> +		if (!itte->pending) {
> +			kfree(itte);
> +			kfree(new_coll);
> +			return -ENOMEM;
> +		}
> +
> +		itte->event_id	= event_id;
> +
> +		list_add_tail(&itte->itte_list, &device->itt);
> +	}
> +
> +	itte->collection = collection ? collection : new_coll;
> +	itte->lpi = lpi_nr;
> +
> +	return 0;
> +}
> +
> +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);
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_mapd(struct kvm *kvm, u64 *its_cmd)
> +{
> +	bool valid = its_cmd_get_validbit(its_cmd);
> +	u32 device_id = its_cmd_get_deviceid(its_cmd);
> +	struct its_device *device;
> +
> +	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)
> +		return 0;
> +
> +	device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
> +	if (!device)
> +		return -ENOMEM;
> +
> +	device->device_id = device_id;
> +	INIT_LIST_HEAD(&device->itt);
> +
> +	list_add_tail(&device->dev_list,
> +		      &kvm->arch.vgic.its.device_list);
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_mapc(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u16 coll_id;
> +	u32 target_addr;
> +	struct its_collection *collection;
> +	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;
> +
> +	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)
> +			return 0;
> +
> +		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);
> +		return 0;
> +	}
> +
> +	if (!collection) {
> +		collection = vits_new_collection(kvm, coll_id);
> +		if (!collection)
> +			return -ENOMEM;
> +	}
> +
> +	collection->target_addr = target_addr;
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_clear(struct kvm *kvm, u64 *its_cmd)
> +{
> +	u32 device_id;
> +	u32 event_id;
> +	struct its_itte *itte;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_CLEAR_UNMAPPED_INTERRUPT;
> +
> +	if (itte->collection)
> +		clear_bit(itte->collection->target_addr, itte->pending);
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +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;
> +	gpa_t propbase;
> +	int ret;
> +	u8 prop;
> +
> +	device_id = its_cmd_get_deviceid(its_cmd);
> +	event_id = its_cmd_get_id(its_cmd);
> +
> +	itte = find_itte(kvm, device_id, event_id);
> +	if (!itte)
> +		return E_ITS_INV_UNMAPPED_INTERRUPT;
> +
> +	propbase = BASER_BASE_ADDRESS(dist->propbaser);
> +	ret = kvm_read_guest(kvm, propbase + itte->lpi - GIC_LPI_OFFSET,
> +			     &prop, 1);
> +	if (ret)
> +		return ret;
> +
> +	update_lpi_property(kvm, itte, prop);
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +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_lpi_properties(kvm);
> +	its_sync_lpi_pending_table(vcpu);
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
> +static int vits_cmd_handle_movall(struct kvm *kvm, u64 *its_cmd)
> +{
> +	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;
> +
> +	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);
> +	}
> +
> +	return 0;
> +}
> +
> +/* Must be called with the ITS lock held. */
>  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_MAPVI:
> +		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 those commands: we are in sync all of the time */
> +		break;
> +	}
> +
> +	return ret;
>  }
>  
>  static bool handle_mmio_gits_cbaser(struct kvm_vcpu *vcpu,
> @@ -532,6 +951,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 cc5d5ff..6152d04 100644
> --- a/virt/kvm/arm/its-emul.h
> +++ b/virt/kvm/arm/its-emul.h
> @@ -36,4 +36,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_MAPVI_UNMAPPED_DEVICE		0x010a04
> +#define E_ITS_MAPVI_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	[flat|nested] 104+ messages in thread

* [PATCH 02/13] KVM: extend struct kvm_msi to hold a 32-bit device ID
  2015-06-28 19:12     ` Christoffer Dall
@ 2015-06-29 14:53       ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-29 14:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

thanks for your time to reviewing this! Was probably no pleasure ;-)

On 28/06/15 20:12, Christoffer Dall wrote:
> On Fri, May 29, 2015 at 10:53:18AM +0100, Andre Przywara wrote:
>> 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.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  Documentation/virtual/kvm/api.txt | 8 ++++++--
>>  include/uapi/linux/kvm.h          | 4 +++-
>>  2 files changed, 9 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
>> index 9fa2bf8..891d64a 100644
>> --- a/Documentation/virtual/kvm/api.txt
>> +++ b/Documentation/virtual/kvm/api.txt
>> @@ -2121,10 +2121,14 @@ 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 is valid, otherwise ignored.
> 
> I don't see what the 'otherwise ignored' part of the sentence here is
> meant to say, that the flags field is otherwise ignored for other value?

No, that the devid field is ignored if this bit isn't set. I can
rephrase this to be more explicit.

> That's not what the current API doc specifies, it specifies that the
> remainder of the field must be 0.
> 
>> +devid: If KVM_MSI_VALID_DEVID is set, contains a value to identify the device
>> +       that wrote the MSI message. For PCI, this is usually a BFD
>> +       identifier in the lower 16 bits.
> 
> I assume plus something else that uniquely identifies the PCI
> controller?

Well yes, the device ID is a unique device identifier within a system,
the BFD use case was just to illustrate this and give a hint to
userspace what to fill in there. I will explain this better in v2.

So are you OK with that extension of the API in general? Just asking
because there is a lot that depends on it.

Cheers,
Andre.

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

* Re: [PATCH 02/13] KVM: extend struct kvm_msi to hold a 32-bit device ID
@ 2015-06-29 14:53       ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-06-29 14:53 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara
  Cc: marc.zyngier, kvmarm, linux-arm-kernel, kvm

Hi Christoffer,

thanks for your time to reviewing this! Was probably no pleasure ;-)

On 28/06/15 20:12, Christoffer Dall wrote:
> On Fri, May 29, 2015 at 10:53:18AM +0100, Andre Przywara wrote:
>> 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.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  Documentation/virtual/kvm/api.txt | 8 ++++++--
>>  include/uapi/linux/kvm.h          | 4 +++-
>>  2 files changed, 9 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
>> index 9fa2bf8..891d64a 100644
>> --- a/Documentation/virtual/kvm/api.txt
>> +++ b/Documentation/virtual/kvm/api.txt
>> @@ -2121,10 +2121,14 @@ 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 is valid, otherwise ignored.
> 
> I don't see what the 'otherwise ignored' part of the sentence here is
> meant to say, that the flags field is otherwise ignored for other value?

No, that the devid field is ignored if this bit isn't set. I can
rephrase this to be more explicit.

> That's not what the current API doc specifies, it specifies that the
> remainder of the field must be 0.
> 
>> +devid: If KVM_MSI_VALID_DEVID is set, contains a value to identify the device
>> +       that wrote the MSI message. For PCI, this is usually a BFD
>> +       identifier in the lower 16 bits.
> 
> I assume plus something else that uniquely identifies the PCI
> controller?

Well yes, the device ID is a unique device identifier within a system,
the BFD use case was just to illustrate this and give a hint to
userspace what to fill in there. I will explain this better in v2.

So are you OK with that extension of the API in general? Just asking
because there is a lot that depends on it.

Cheers,
Andre.

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

* [PATCH 02/13] KVM: extend struct kvm_msi to hold a 32-bit device ID
  2015-06-29 14:53       ` Andre Przywara
@ 2015-06-29 15:02         ` Christoffer Dall
  -1 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-29 15:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 29, 2015 at 03:53:12PM +0100, Andre Przywara wrote:
> Hi Christoffer,
> 
> thanks for your time to reviewing this! Was probably no pleasure ;-)
> 
> On 28/06/15 20:12, Christoffer Dall wrote:
> > On Fri, May 29, 2015 at 10:53:18AM +0100, Andre Przywara wrote:
> >> 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.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  Documentation/virtual/kvm/api.txt | 8 ++++++--
> >>  include/uapi/linux/kvm.h          | 4 +++-
> >>  2 files changed, 9 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> >> index 9fa2bf8..891d64a 100644
> >> --- a/Documentation/virtual/kvm/api.txt
> >> +++ b/Documentation/virtual/kvm/api.txt
> >> @@ -2121,10 +2121,14 @@ 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 is valid, otherwise ignored.
> > 
> > I don't see what the 'otherwise ignored' part of the sentence here is
> > meant to say, that the flags field is otherwise ignored for other value?
> 
> No, that the devid field is ignored if this bit isn't set. I can
> rephrase this to be more explicit.
> 
> > That's not what the current API doc specifies, it specifies that the
> > remainder of the field must be 0.
> > 
> >> +devid: If KVM_MSI_VALID_DEVID is set, contains a value to identify the device
> >> +       that wrote the MSI message. For PCI, this is usually a BFD
> >> +       identifier in the lower 16 bits.
> > 
> > I assume plus something else that uniquely identifies the PCI
> > controller?
> 
> Well yes, the device ID is a unique device identifier within a system,
> the BFD use case was just to illustrate this and give a hint to
> userspace what to fill in there. I will explain this better in v2.
> 
> So are you OK with that extension of the API in general? Just asking
> because there is a lot that depends on it.
> 
Yeah, I didn't review the series in detail yet, but the API change looks
ok to me.

-Christoffer

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

* Re: [PATCH 02/13] KVM: extend struct kvm_msi to hold a 32-bit device ID
@ 2015-06-29 15:02         ` Christoffer Dall
  0 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-06-29 15:02 UTC (permalink / raw)
  To: Andre Przywara; +Cc: marc.zyngier, kvmarm, linux-arm-kernel, kvm

On Mon, Jun 29, 2015 at 03:53:12PM +0100, Andre Przywara wrote:
> Hi Christoffer,
> 
> thanks for your time to reviewing this! Was probably no pleasure ;-)
> 
> On 28/06/15 20:12, Christoffer Dall wrote:
> > On Fri, May 29, 2015 at 10:53:18AM +0100, Andre Przywara wrote:
> >> 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.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  Documentation/virtual/kvm/api.txt | 8 ++++++--
> >>  include/uapi/linux/kvm.h          | 4 +++-
> >>  2 files changed, 9 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> >> index 9fa2bf8..891d64a 100644
> >> --- a/Documentation/virtual/kvm/api.txt
> >> +++ b/Documentation/virtual/kvm/api.txt
> >> @@ -2121,10 +2121,14 @@ 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 is valid, otherwise ignored.
> > 
> > I don't see what the 'otherwise ignored' part of the sentence here is
> > meant to say, that the flags field is otherwise ignored for other value?
> 
> No, that the devid field is ignored if this bit isn't set. I can
> rephrase this to be more explicit.
> 
> > That's not what the current API doc specifies, it specifies that the
> > remainder of the field must be 0.
> > 
> >> +devid: If KVM_MSI_VALID_DEVID is set, contains a value to identify the device
> >> +       that wrote the MSI message. For PCI, this is usually a BFD
> >> +       identifier in the lower 16 bits.
> > 
> > I assume plus something else that uniquely identifies the PCI
> > controller?
> 
> Well yes, the device ID is a unique device identifier within a system,
> the BFD use case was just to illustrate this and give a hint to
> userspace what to fill in there. I will explain this better in v2.
> 
> So are you OK with that extension of the API in general? Just asking
> because there is a lot that depends on it.
> 
Yeah, I didn't review the series in detail yet, but the API change looks
ok to me.

-Christoffer

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

* [PATCH 11/13] KVM: arm64: implement ITS command queue command handlers
  2015-06-28 19:41     ` Christoffer Dall
@ 2015-07-03 15:57       ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-07-03 15:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

....

>> +
>> +static struct its_collection *vits_new_collection(struct kvm *kvm, u32 coll_id)
>> +{
>> +	struct its_collection *collection;
>> +
>> +	collection = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
> 
> If I manage to understand the structure here, you're calling all these
> handler functions with a spinlock held so any operation that may sleep
> could cause your system to deadlock.
> 
> I'll stop looking for these and recommend you go over the whole series
> for these.

Do you reckon it would be sufficient to just avoid the kmallocs inside
the lock? For this case above we could go with some storage space
preallocated outside of the lock (I hope).

> 
> Perhaps the right thing to do is to synchronize access to your data
> structure (why you hold the spinlock right?) with RCU if you can...

Well, the point is that there is not one ITS data structure, but it's a
mesh of lists connected to each other. I'd like to avoid going down with
RCU there, so I'd like to keep it all under one lock.
I wonder if this could be mutex_lock_interruptible, though. From the top
of your head, is there anything that would prevent that? I reckon ITS
access contention is rather rare (though possible), so a sleeping VCPU
wouldn't harm us so much in practice, would it?

Cheers,
Andre.

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

* Re: [PATCH 11/13] KVM: arm64: implement ITS command queue command handlers
@ 2015-07-03 15:57       ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-07-03 15:57 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara
  Cc: marc.zyngier, kvmarm, linux-arm-kernel, kvm

Hi Christoffer,

....

>> +
>> +static struct its_collection *vits_new_collection(struct kvm *kvm, u32 coll_id)
>> +{
>> +	struct its_collection *collection;
>> +
>> +	collection = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
> 
> If I manage to understand the structure here, you're calling all these
> handler functions with a spinlock held so any operation that may sleep
> could cause your system to deadlock.
> 
> I'll stop looking for these and recommend you go over the whole series
> for these.

Do you reckon it would be sufficient to just avoid the kmallocs inside
the lock? For this case above we could go with some storage space
preallocated outside of the lock (I hope).

> 
> Perhaps the right thing to do is to synchronize access to your data
> structure (why you hold the spinlock right?) with RCU if you can...

Well, the point is that there is not one ITS data structure, but it's a
mesh of lists connected to each other. I'd like to avoid going down with
RCU there, so I'd like to keep it all under one lock.
I wonder if this could be mutex_lock_interruptible, though. From the top
of your head, is there anything that would prevent that? I reckon ITS
access contention is rather rare (though possible), so a sleeping VCPU
wouldn't harm us so much in practice, would it?

Cheers,
Andre.

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

* [PATCH 11/13] KVM: arm64: implement ITS command queue command handlers
  2015-07-03 15:57       ` Andre Przywara
@ 2015-07-03 21:01         ` Christoffer Dall
  -1 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-07-03 21:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 03, 2015 at 04:57:04PM +0100, Andre Przywara wrote:
> Hi Christoffer,
> 
> ....
> 
> >> +
> >> +static struct its_collection *vits_new_collection(struct kvm *kvm, u32 coll_id)
> >> +{
> >> +	struct its_collection *collection;
> >> +
> >> +	collection = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
> > 
> > If I manage to understand the structure here, you're calling all these
> > handler functions with a spinlock held so any operation that may sleep
> > could cause your system to deadlock.
> > 
> > I'll stop looking for these and recommend you go over the whole series
> > for these.
> 
> Do you reckon it would be sufficient to just avoid the kmallocs inside
> the lock? For this case above we could go with some storage space
> preallocated outside of the lock (I hope).
> 

Yes, you can preallocate or you need to grab a mutex instead of a
spinlock...

> > 
> > Perhaps the right thing to do is to synchronize access to your data
> > structure (why you hold the spinlock right?) with RCU if you can...
> 
> Well, the point is that there is not one ITS data structure, but it's a
> mesh of lists connected to each other. I'd like to avoid going down with
> RCU there, so I'd like to keep it all under one lock.
> I wonder if this could be mutex_lock_interruptible, though. From the top
> of your head, is there anything that would prevent that? I reckon ITS
> access contention is rather rare (though possible), so a sleeping VCPU
> wouldn't harm us so much in practice, would it?
> 
We know from experience from x86 that one of the things they had to look
at was to get the run-loop lock-free, and we went through a lot of
effort to do that on ARM too.  Along came the vgic and that was out the
window, and now it feels like we're just grabbing spinlocks all over the
place.

I'm fine with a mutex if other solutions are not easy/possible and it's
in a truly non-critical path, but I wouldn't to speculate about the
level of contention at this point without profiling something.

In any case, let's fix the potential host-kernel deadlock issues in the
most elegant way first and let's try to think about not grabbing too
many spinlocks in this code and take it from there.

Thanks,
-Christoffer

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

* Re: [PATCH 11/13] KVM: arm64: implement ITS command queue command handlers
@ 2015-07-03 21:01         ` Christoffer Dall
  0 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-07-03 21:01 UTC (permalink / raw)
  To: Andre Przywara; +Cc: marc.zyngier, kvmarm, linux-arm-kernel, kvm

On Fri, Jul 03, 2015 at 04:57:04PM +0100, Andre Przywara wrote:
> Hi Christoffer,
> 
> ....
> 
> >> +
> >> +static struct its_collection *vits_new_collection(struct kvm *kvm, u32 coll_id)
> >> +{
> >> +	struct its_collection *collection;
> >> +
> >> +	collection = kmalloc(sizeof(struct its_collection), GFP_KERNEL);
> > 
> > If I manage to understand the structure here, you're calling all these
> > handler functions with a spinlock held so any operation that may sleep
> > could cause your system to deadlock.
> > 
> > I'll stop looking for these and recommend you go over the whole series
> > for these.
> 
> Do you reckon it would be sufficient to just avoid the kmallocs inside
> the lock? For this case above we could go with some storage space
> preallocated outside of the lock (I hope).
> 

Yes, you can preallocate or you need to grab a mutex instead of a
spinlock...

> > 
> > Perhaps the right thing to do is to synchronize access to your data
> > structure (why you hold the spinlock right?) with RCU if you can...
> 
> Well, the point is that there is not one ITS data structure, but it's a
> mesh of lists connected to each other. I'd like to avoid going down with
> RCU there, so I'd like to keep it all under one lock.
> I wonder if this could be mutex_lock_interruptible, though. From the top
> of your head, is there anything that would prevent that? I reckon ITS
> access contention is rather rare (though possible), so a sleeping VCPU
> wouldn't harm us so much in practice, would it?
> 
We know from experience from x86 that one of the things they had to look
at was to get the run-loop lock-free, and we went through a lot of
effort to do that on ARM too.  Along came the vgic and that was out the
window, and now it feels like we're just grabbing spinlocks all over the
place.

I'm fine with a mutex if other solutions are not easy/possible and it's
in a truly non-critical path, but I wouldn't to speculate about the
level of contention at this point without profiling something.

In any case, let's fix the potential host-kernel deadlock issues in the
most elegant way first and let's try to think about not grabbing too
many spinlocks in this code and take it from there.

Thanks,
-Christoffer

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

* [PATCH 12/13] KVM: arm64: implement MSI injection in ITS emulation
  2015-06-11 17:43     ` Eric Auger
@ 2015-07-06 16:46       ` Andre Przywara
  -1 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-07-06 16:46 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 574cf05..35e886c 100644
>> --- a/virt/kvm/arm/its-emul.c
>> +++ b/virt/kvm/arm/its-emul.c
>> @@ -340,6 +340,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);
> so now the internal state is different from the pending state in ext
> memory. I don't really understand where the ext mem is used?

This is expected, as the ITS is allowed to cache the state. In a
hardware ITS implementation the external memory is used to provide
actual storage for the ITS, something we do not need for the emulation,
as we have cheaper (host) memory for that.
The only thing we have to model though is that the guest may use the
external storage to take a snapshot of the current state, but it may
only do so after having flushed the ITS "cache", which means we
synchronize our internal data structures to that "external" memory.

>> +	inject = itte->enabled;
>> +
>> +out_unlock:
>> +	spin_unlock(&its->lock);
>> +
>> +	if (inject) {
>> +		spin_lock(&dist->lock);
>> +		set_bit(cpuid, dist->irq_pending_on_cpu);
> isn't it atomic op?

It is, but that's not what the lock protects. It's there to avoid
stepping on someone else's toes, who might deal with the ITS data
structures at the same time and would not expect a value to change in
the middle (think about code iterating over dist->irq_pending_on_cpu).

Cheers,
Andre.

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

* Re: [PATCH 12/13] KVM: arm64: implement MSI injection in ITS emulation
@ 2015-07-06 16:46       ` Andre Przywara
  0 siblings, 0 replies; 104+ messages in thread
From: Andre Przywara @ 2015-07-06 16:46 UTC (permalink / raw)
  To: Eric Auger
  Cc: Marc Zyngier, kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu,
	linux-arm-kernel@lists.infradead.org

Hi Eric,

....

>> diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c
>> index 574cf05..35e886c 100644
>> --- a/virt/kvm/arm/its-emul.c
>> +++ b/virt/kvm/arm/its-emul.c
>> @@ -340,6 +340,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);
> so now the internal state is different from the pending state in ext
> memory. I don't really understand where the ext mem is used?

This is expected, as the ITS is allowed to cache the state. In a
hardware ITS implementation the external memory is used to provide
actual storage for the ITS, something we do not need for the emulation,
as we have cheaper (host) memory for that.
The only thing we have to model though is that the guest may use the
external storage to take a snapshot of the current state, but it may
only do so after having flushed the ITS "cache", which means we
synchronize our internal data structures to that "external" memory.

>> +	inject = itte->enabled;
>> +
>> +out_unlock:
>> +	spin_unlock(&its->lock);
>> +
>> +	if (inject) {
>> +		spin_lock(&dist->lock);
>> +		set_bit(cpuid, dist->irq_pending_on_cpu);
> isn't it atomic op?

It is, but that's not what the lock protects. It's there to avoid
stepping on someone else's toes, who might deal with the ITS data
structures at the same time and would not expect a value to change in
the middle (think about code iterating over dist->irq_pending_on_cpu).

Cheers,
Andre.

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

* [PATCH 12/13] KVM: arm64: implement MSI injection in ITS emulation
  2015-07-06 16:46       ` Andre Przywara
@ 2015-07-07  8:13         ` Christoffer Dall
  -1 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-07-07  8:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 06, 2015 at 05:46:37PM +0100, Andre Przywara wrote:

[...]

> 
> >> +	inject = itte->enabled;
> >> +
> >> +out_unlock:
> >> +	spin_unlock(&its->lock);
> >> +
> >> +	if (inject) {
> >> +		spin_lock(&dist->lock);
> >> +		set_bit(cpuid, dist->irq_pending_on_cpu);
> > isn't it atomic op?
> 
> It is, but that's not what the lock protects. It's there to avoid
> stepping on someone else's toes, who might deal with the ITS data
> structures at the same time and would not expect a value to change in
> the middle (think about code iterating over dist->irq_pending_on_cpu).
> 
then should it be __set_bit ?

-Christoffer

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

* Re: [PATCH 12/13] KVM: arm64: implement MSI injection in ITS emulation
@ 2015-07-07  8:13         ` Christoffer Dall
  0 siblings, 0 replies; 104+ messages in thread
From: Christoffer Dall @ 2015-07-07  8:13 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Eric Auger, Marc Zyngier, kvmarm@lists.cs.columbia.edu,
	linux-arm-kernel@lists.infradead.org, kvm@vger.kernel.org

On Mon, Jul 06, 2015 at 05:46:37PM +0100, Andre Przywara wrote:

[...]

> 
> >> +	inject = itte->enabled;
> >> +
> >> +out_unlock:
> >> +	spin_unlock(&its->lock);
> >> +
> >> +	if (inject) {
> >> +		spin_lock(&dist->lock);
> >> +		set_bit(cpuid, dist->irq_pending_on_cpu);
> > isn't it atomic op?
> 
> It is, but that's not what the lock protects. It's there to avoid
> stepping on someone else's toes, who might deal with the ITS data
> structures at the same time and would not expect a value to change in
> the middle (think about code iterating over dist->irq_pending_on_cpu).
> 
then should it be __set_bit ?

-Christoffer

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

end of thread, other threads:[~2015-07-07  8:13 UTC | newest]

Thread overview: 104+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-29  9:53 [PATCH 00/13] arm64: KVM: GICv3 ITS emulation Andre Przywara
2015-05-29  9:53 ` Andre Przywara
2015-05-29  9:53 ` [PATCH 01/13] KVM: arm/arm64: VGIC: don't track used LRs in the distributor Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-12 17:23   ` Eric Auger
2015-05-29  9:53 ` [PATCH 02/13] KVM: extend struct kvm_msi to hold a 32-bit device ID Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-09  8:49   ` Eric Auger
2015-06-09  8:49     ` Eric Auger
2015-06-28 19:12   ` Christoffer Dall
2015-06-28 19:12     ` Christoffer Dall
2015-06-29 14:53     ` Andre Przywara
2015-06-29 14:53       ` Andre Przywara
2015-06-29 15:02       ` Christoffer Dall
2015-06-29 15:02         ` Christoffer Dall
2015-05-29  9:53 ` [PATCH 03/13] KVM: arm/arm64: add emulation model specific destroy function Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-09  8:51   ` Eric Auger
2015-06-09  8:51     ` Eric Auger
2015-06-28 19:14   ` Christoffer Dall
2015-06-28 19:14     ` Christoffer Dall
2015-05-29  9:53 ` [PATCH 04/13] KVM: arm64: Introduce new MMIO region for the ITS base address Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-09  8:52   ` Eric Auger
2015-06-09  8:52     ` Eric Auger
2015-06-11 15:12     ` Andre Przywara
2015-06-11 15:12       ` Andre Przywara
2015-05-29  9:53 ` [PATCH 05/13] KVM: arm64: handle ITS related GICv3 redistributor registers Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-09  8:52   ` Eric Auger
2015-06-09  8:52     ` Eric Auger
2015-06-12 17:03     ` Andre Przywara
2015-06-12 17:03       ` Andre Przywara
2015-05-29  9:53 ` [PATCH 06/13] KVM: arm64: introduce ITS emulation file with stub functions Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-09  9:23   ` Eric Auger
2015-06-09  9:23     ` Eric Auger
2015-05-29  9:53 ` [PATCH 07/13] KVM: arm64: implement basic ITS register handlers Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-09 13:34   ` Eric Auger
2015-06-09 13:34     ` Eric Auger
2015-06-28 19:36   ` Christoffer Dall
2015-06-28 19:36     ` Christoffer Dall
2015-05-29  9:53 ` [PATCH 08/13] KVM: arm64: add data structures to model ITS interrupt translation Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-09 15:59   ` Eric Auger
2015-06-09 15:59     ` Eric Auger
2015-05-29  9:53 ` [PATCH 09/13] KVM: arm64: handle pending bit for LPIs in ITS emulation Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-09 15:59   ` Eric Auger
2015-06-09 15:59     ` Eric Auger
2015-06-11 15:46     ` Andre Przywara
2015-06-11 15:46       ` Andre Przywara
2015-06-11 16:01       ` Marc Zyngier
2015-06-11 16:01         ` Marc Zyngier
2015-06-11 18:24         ` Eric Auger
2015-06-11 18:24           ` Eric Auger
2015-05-29  9:53 ` [PATCH 10/13] KVM: arm64: sync LPI properties and status between guest and KVM Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-11 17:44   ` Eric Auger
2015-06-11 17:44     ` Eric Auger
2015-06-28 19:33   ` Christoffer Dall
2015-06-28 19:33     ` Christoffer Dall
2015-05-29  9:53 ` [PATCH 11/13] KVM: arm64: implement ITS command queue command handlers Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-12 15:28   ` Eric Auger
2015-06-12 15:28     ` Eric Auger
2015-06-28 19:41   ` Christoffer Dall
2015-06-28 19:41     ` Christoffer Dall
2015-07-03 15:57     ` Andre Przywara
2015-07-03 15:57       ` Andre Przywara
2015-07-03 21:01       ` Christoffer Dall
2015-07-03 21:01         ` Christoffer Dall
2015-05-29  9:53 ` [PATCH 12/13] KVM: arm64: implement MSI injection in ITS emulation Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-11 17:43   ` Eric Auger
2015-06-11 17:43     ` Eric Auger
2015-07-06 16:46     ` Andre Przywara
2015-07-06 16:46       ` Andre Przywara
2015-07-07  8:13       ` Christoffer Dall
2015-07-07  8:13         ` Christoffer Dall
2015-05-29  9:53 ` [PATCH 13/13] KVM: arm64: enable ITS emulation as a virtual MSI controller Andre Przywara
2015-05-29  9:53   ` Andre Przywara
2015-06-12 16:05   ` Eric Auger
2015-06-12 16:05     ` Eric Auger
2015-06-18  8:43   ` Eric Auger
2015-06-18  8:43     ` Eric Auger
2015-06-18 14:22     ` Andre Przywara
2015-06-18 14:22       ` Andre Przywara
2015-06-18 15:03       ` Pavel Fedin
2015-06-18 15:03         ` Pavel Fedin
2015-06-18 19:20         ` Andre Przywara
2015-06-18 19:20           ` Andre Przywara
2015-06-08  6:53 ` [PATCH 00/13] arm64: KVM: GICv3 ITS emulation Pavel Fedin
2015-06-08  6:53   ` Pavel Fedin
2015-06-08  8:23   ` Marc Zyngier
2015-06-08  8:23     ` Marc Zyngier
2015-06-08 10:54     ` Pavel Fedin
2015-06-08 10:54       ` Pavel Fedin
2015-06-08 17:13       ` Marc Zyngier
2015-06-08 17:13         ` Marc Zyngier
2015-06-09  8:12       ` Eric Auger
2015-06-09  8:12         ` Eric Auger
2015-06-10 12:18 ` Pavel Fedin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.