All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-25  2:04 ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: kvmarm, kvm, linux-arm-kernel

This series is a joint effort to re-implement KVM's GIC emulation.

While the current implementation is centered around providing
efficient MMIO emulation, the hot path for most guests is actually
the guest entry and exit, which currently is rather costly.
Also the existing emulation has a global distributor lock, which
quickly becomes a bottleneck once the number of VCPUs increases.
Additionally the emulation was originally designed for GICv2, adding
GICv3 ITS emulation support to this proved to be rather painful.
Last, but not least the existing code became less and less
maintainable, with many special cases handled explicitly.

The new implementation is build around a struct vgic_irq data data
structure, which holds all information about a virtual interrupt.
Interruts which should be injected are hold in a per-VCPU list, this
make the entry/exit path much more efficient. Also the new structure
allows to have more fine grained locking - per IRQ and per VCPU -
getting rid of the global distributor lock.
As a result of the new design ITS emulation fits in more nicely, the
respective code will be provided as a follow-up series.

This series implements the same feature set as the existing emulation,
as a goodie we now implement priorities correctly.
To allow an easy transition with good test coverage, but still maintain
stability, both implementations live side by side, selectable via a
Kconfig option. The default is the new implementation.
If this code proves to be reliable, we will later remove the current
implementation with an extra patch set.

Please have a look at the series, review it and give the code some
serious testing (and possibly debugging). All feedback is appreciated.

Cheers,
Andre.

Andre Przywara (26):
  KVM: arm/arm64: add missing MMIO data write-back
  KVM: arm/arm64: pmu: abstract access to number of SPIs
  KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface
  KVM: arm/arm64: vgic-new: Add MMIO handling framework
  KVM: arm/arm64: vgic-new: Export register access interface
  KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  KVM: arm/arm64: vgic-new: Add PENDING registers handlers
  KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
  KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
  KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
  KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  KVM: arm/arm64: vgic-new: Add SGIR register handler
  KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
  KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
  KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
  KVM: arm/arm64: vgic-new: Add GICv3 redistributor TYPER handler
  KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
  KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
  KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
  KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
  KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
  KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  KVM: arm/arm64: vgic-new: implement mapped IRQ handling
  KVM: arm/arm64: vgic-new: Add dummy MSI implementation
  KVM: arm/arm64: vgic-new: enable build

Christoffer Dall (5):
  KVM: arm/arm64: vgic-new: Add data structure definitions
  KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq
    instance
  KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity
  KVM: arm/arm64: vgic-new: Add IRQ sorting

Eric Auger (12):
  KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
  KVM: arm/arm64: vgic-new: vgic_kvm_device:
    KVM_DEV_ARM_VGIC_GRP_NR_IRQS
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
  KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
  KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
  KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
  KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
  KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
  KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
  KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable

Marc Zyngier (2):
  KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
  KVM: arm/arm64: vgic-new: Add GICv3 world switch backend

 arch/arm/kvm/Kconfig                |    7 +
 arch/arm/kvm/Makefile               |   10 +
 arch/arm/kvm/mmio.c                 |    2 +-
 arch/arm64/kvm/Kconfig              |    7 +
 arch/arm64/kvm/Makefile             |   10 +
 include/kvm/arm_vgic.h              |   14 +-
 include/kvm/vgic/vgic.h             |  256 +++++++
 virt/kvm/arm/arch_timer.c           |   11 +-
 virt/kvm/arm/pmu.c                  |    2 +-
 virt/kvm/arm/vgic.c                 |   18 +-
 virt/kvm/arm/vgic/vgic-v2.c         |  381 +++++++++++
 virt/kvm/arm/vgic/vgic-v3.c         |  357 ++++++++++
 virt/kvm/arm/vgic/vgic.c            |  614 +++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |  136 ++++
 virt/kvm/arm/vgic/vgic_init.c       |  447 ++++++++++++
 virt/kvm/arm/vgic/vgic_irqfd.c      |   51 ++
 virt/kvm/arm/vgic/vgic_kvm_device.c |  522 ++++++++++++++
 virt/kvm/arm/vgic/vgic_mmio.c       | 1277 +++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic_mmio.h       |   47 ++
 19 files changed, 4149 insertions(+), 20 deletions(-)
 create mode 100644 include/kvm/vgic/vgic.h
 create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
 create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
 create mode 100644 virt/kvm/arm/vgic/vgic.c
 create mode 100644 virt/kvm/arm/vgic/vgic.h
 create mode 100644 virt/kvm/arm/vgic/vgic_init.c
 create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
 create mode 100644 virt/kvm/arm/vgic/vgic_kvm_device.c
 create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
 create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h

-- 
2.7.3


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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-25  2:04 ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

This series is a joint effort to re-implement KVM's GIC emulation.

While the current implementation is centered around providing
efficient MMIO emulation, the hot path for most guests is actually
the guest entry and exit, which currently is rather costly.
Also the existing emulation has a global distributor lock, which
quickly becomes a bottleneck once the number of VCPUs increases.
Additionally the emulation was originally designed for GICv2, adding
GICv3 ITS emulation support to this proved to be rather painful.
Last, but not least the existing code became less and less
maintainable, with many special cases handled explicitly.

The new implementation is build around a struct vgic_irq data data
structure, which holds all information about a virtual interrupt.
Interruts which should be injected are hold in a per-VCPU list, this
make the entry/exit path much more efficient. Also the new structure
allows to have more fine grained locking - per IRQ and per VCPU -
getting rid of the global distributor lock.
As a result of the new design ITS emulation fits in more nicely, the
respective code will be provided as a follow-up series.

This series implements the same feature set as the existing emulation,
as a goodie we now implement priorities correctly.
To allow an easy transition with good test coverage, but still maintain
stability, both implementations live side by side, selectable via a
Kconfig option. The default is the new implementation.
If this code proves to be reliable, we will later remove the current
implementation with an extra patch set.

Please have a look at the series, review it and give the code some
serious testing (and possibly debugging). All feedback is appreciated.

Cheers,
Andre.

Andre Przywara (26):
  KVM: arm/arm64: add missing MMIO data write-back
  KVM: arm/arm64: pmu: abstract access to number of SPIs
  KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface
  KVM: arm/arm64: vgic-new: Add MMIO handling framework
  KVM: arm/arm64: vgic-new: Export register access interface
  KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  KVM: arm/arm64: vgic-new: Add PENDING registers handlers
  KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
  KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
  KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
  KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  KVM: arm/arm64: vgic-new: Add SGIR register handler
  KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
  KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
  KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
  KVM: arm/arm64: vgic-new: Add GICv3 redistributor TYPER handler
  KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
  KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
  KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
  KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
  KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
  KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  KVM: arm/arm64: vgic-new: implement mapped IRQ handling
  KVM: arm/arm64: vgic-new: Add dummy MSI implementation
  KVM: arm/arm64: vgic-new: enable build

Christoffer Dall (5):
  KVM: arm/arm64: vgic-new: Add data structure definitions
  KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq
    instance
  KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity
  KVM: arm/arm64: vgic-new: Add IRQ sorting

Eric Auger (12):
  KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
  KVM: arm/arm64: vgic-new: vgic_kvm_device:
    KVM_DEV_ARM_VGIC_GRP_NR_IRQS
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
  KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
  KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
  KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
  KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
  KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
  KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
  KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable

Marc Zyngier (2):
  KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
  KVM: arm/arm64: vgic-new: Add GICv3 world switch backend

 arch/arm/kvm/Kconfig                |    7 +
 arch/arm/kvm/Makefile               |   10 +
 arch/arm/kvm/mmio.c                 |    2 +-
 arch/arm64/kvm/Kconfig              |    7 +
 arch/arm64/kvm/Makefile             |   10 +
 include/kvm/arm_vgic.h              |   14 +-
 include/kvm/vgic/vgic.h             |  256 +++++++
 virt/kvm/arm/arch_timer.c           |   11 +-
 virt/kvm/arm/pmu.c                  |    2 +-
 virt/kvm/arm/vgic.c                 |   18 +-
 virt/kvm/arm/vgic/vgic-v2.c         |  381 +++++++++++
 virt/kvm/arm/vgic/vgic-v3.c         |  357 ++++++++++
 virt/kvm/arm/vgic/vgic.c            |  614 +++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |  136 ++++
 virt/kvm/arm/vgic/vgic_init.c       |  447 ++++++++++++
 virt/kvm/arm/vgic/vgic_irqfd.c      |   51 ++
 virt/kvm/arm/vgic/vgic_kvm_device.c |  522 ++++++++++++++
 virt/kvm/arm/vgic/vgic_mmio.c       | 1277 +++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic_mmio.h       |   47 ++
 19 files changed, 4149 insertions(+), 20 deletions(-)
 create mode 100644 include/kvm/vgic/vgic.h
 create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
 create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
 create mode 100644 virt/kvm/arm/vgic/vgic.c
 create mode 100644 virt/kvm/arm/vgic/vgic.h
 create mode 100644 virt/kvm/arm/vgic/vgic_init.c
 create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
 create mode 100644 virt/kvm/arm/vgic/vgic_kvm_device.c
 create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
 create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h

-- 
2.7.3

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

* [RFC PATCH 01/45] KVM: arm/arm64: add missing MMIO data write-back
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: kvmarm, kvm, linux-arm-kernel

When the kernel was handling a guest MMIO access internally, we need
to copy the emulation result into the run->mmio structure in order
for the kvm_handle_mmio_return() function to pick it up and inject
the result back into the guest.
Currently the only user of kvm_io_bus for ARM is the VGIC, which did
this copying itself, so this was not causing issues so far.
But with upcoming kvm_io_bus users we need to do the copying here.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/kvm/mmio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 0f6600f..d5c2727 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -206,7 +206,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	run->mmio.is_write	= is_write;
 	run->mmio.phys_addr	= fault_ipa;
 	run->mmio.len		= len;
-	if (is_write)
+	if (is_write || !ret)
 		memcpy(run->mmio.data, data_buf, len);
 
 	if (!ret) {
-- 
2.7.3


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

* [RFC PATCH 01/45] KVM: arm/arm64: add missing MMIO data write-back
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

When the kernel was handling a guest MMIO access internally, we need
to copy the emulation result into the run->mmio structure in order
for the kvm_handle_mmio_return() function to pick it up and inject
the result back into the guest.
Currently the only user of kvm_io_bus for ARM is the VGIC, which did
this copying itself, so this was not causing issues so far.
But with upcoming kvm_io_bus users we need to do the copying here.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/kvm/mmio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 0f6600f..d5c2727 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -206,7 +206,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	run->mmio.is_write	= is_write;
 	run->mmio.phys_addr	= fault_ipa;
 	run->mmio.len		= len;
-	if (is_write)
+	if (is_write || !ret)
 		memcpy(run->mmio.data, data_buf, len);
 
 	if (!ret) {
-- 
2.7.3

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

* [RFC PATCH 02/45] KVM: arm/arm64: pmu: abstract access to number of SPIs
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Currently the PMU uses a member of the struct vgic_dist directly,
which not only breaks abstraction, but will fail with the new VGIC.
Abstract this access in the VGIC header file.

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

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 13a3d53..2b89e27 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -356,6 +356,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
 #define vgic_ready(k)		((k)->arch.vgic.ready)
+#define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+				 ((i) < (k)->arch.vgic.nr_irqs))
 
 int vgic_v2_probe(struct device_node *vgic_node,
 		  const struct vgic_ops **ops,
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index b5754c6..0b2c1fa 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -476,7 +476,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 		 * the interrupt number is the same for all vcpus, while as an
 		 * SPI it must be a separate number per vcpu.
 		 */
-		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
+		if (irq < VGIC_NR_SGIS || !vgic_valid_spi(vcpu->kvm, irq) ||
 		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
 			return -EINVAL;
 
-- 
2.7.3

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

* [RFC PATCH 02/45] KVM: arm/arm64: pmu: abstract access to number of SPIs
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Currently the PMU uses a member of the struct vgic_dist directly,
which not only breaks abstraction, but will fail with the new VGIC.
Abstract this access in the VGIC header file.

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

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 13a3d53..2b89e27 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -356,6 +356,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
 #define vgic_ready(k)		((k)->arch.vgic.ready)
+#define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+				 ((i) < (k)->arch.vgic.nr_irqs))
 
 int vgic_v2_probe(struct device_node *vgic_node,
 		  const struct vgic_ops **ops,
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index b5754c6..0b2c1fa 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -476,7 +476,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 		 * the interrupt number is the same for all vcpus, while as an
 		 * SPI it must be a separate number per vcpu.
 		 */
-		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
+		if (irq < VGIC_NR_SGIS || !vgic_valid_spi(vcpu->kvm, irq) ||
 		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
 			return -EINVAL;
 
-- 
2.7.3

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

* [RFC PATCH 03/45] KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: kvmarm, kvm, linux-arm-kernel

Adapt the interface between the virtualized arch timer and the
emulated VGIC to avoid the phys_map when possible.
This prepares the arch timer to go with both the existing VGIC
implementation and the new version later without too many code
changes.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h    |  7 ++++---
 virt/kvm/arm/arch_timer.c | 11 +++++------
 virt/kvm/arm/vgic.c       | 18 +++++++++---------
 3 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 2b89e27..7656a46 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -345,13 +345,14 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
 			bool level);
 int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
-			       struct irq_phys_map *map, bool level);
+			       int virt_irq, bool level);
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 					   int virt_irq, int irq);
-int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
-bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
+			    int virt_irq);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, int virt_irq);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index a9ad4fe..74e3d4b 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -137,10 +137,10 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
 
 	timer->active_cleared_last = false;
 	timer->irq.level = new_level;
-	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->map->virt_irq,
+	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq,
 				   timer->irq.level);
 	ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
-					 timer->map,
+					 timer->irq.irq,
 					 timer->irq.level);
 	WARN_ON(ret);
 }
@@ -246,7 +246,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	* to ensure that hardware interrupts from the timer triggers a guest
 	* exit.
 	*/
-	if (timer->irq.level || kvm_vgic_map_is_active(vcpu, timer->map))
+	if (timer->irq.level || kvm_vgic_map_is_active(vcpu, timer->irq.irq))
 		phys_active = true;
 	else
 		phys_active = false;
@@ -274,7 +274,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	if (timer->active_cleared_last && !phys_active)
 		return;
 
-	ret = irq_set_irqchip_state(timer->map->irq,
+	ret = irq_set_irqchip_state(host_vtimer_irq,
 				    IRQCHIP_STATE_ACTIVE,
 				    phys_active);
 	WARN_ON(ret);
@@ -476,8 +476,7 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 
 	timer_disarm(timer);
-	if (timer->map)
-		kvm_vgic_unmap_phys_irq(vcpu, timer->map);
+	kvm_vgic_unmap_phys_irq(vcpu, timer->map, timer->irq.irq);
 }
 
 void kvm_timer_enable(struct kvm *kvm)
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00429b3..079b0a7 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1103,18 +1103,18 @@ static bool dist_active_irq(struct kvm_vcpu *vcpu)
 	return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu);
 }
 
-bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map)
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, int virt_irq)
 {
 	int i;
 
 	for (i = 0; i < vcpu->arch.vgic_cpu.nr_lr; i++) {
 		struct vgic_lr vlr = vgic_get_lr(vcpu, i);
 
-		if (vlr.irq == map->virt_irq && vlr.state & LR_STATE_ACTIVE)
+		if (vlr.irq == virt_irq && vlr.state & LR_STATE_ACTIVE)
 			return true;
 	}
 
-	return vgic_irq_is_active(vcpu, map->virt_irq);
+	return vgic_irq_is_active(vcpu, virt_irq);
 }
 
 /*
@@ -1522,7 +1522,6 @@ static int vgic_validate_injection(struct kvm_vcpu *vcpu, int irq, int level)
 }
 
 static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
-				   struct irq_phys_map *map,
 				   unsigned int irq_num, bool level)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
@@ -1661,14 +1660,14 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
 	if (map)
 		return -EINVAL;
 
-	return vgic_update_irq_pending(kvm, cpuid, NULL, irq_num, level);
+	return vgic_update_irq_pending(kvm, cpuid, irq_num, level);
 }
 
 /**
  * kvm_vgic_inject_mapped_irq - Inject a physically mapped IRQ to the vgic
  * @kvm:     The VM structure pointer
  * @cpuid:   The CPU for PPIs
- * @map:     Pointer to a irq_phys_map structure describing the mapping
+ * @virt_irq: The virtual IRQ to be injected
  * @level:   Edge-triggered:  true:  to trigger the interrupt
  *			      false: to ignore the call
  *	     Level-sensitive  true:  raise the input signal
@@ -1679,7 +1678,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
  * being HIGH and 0 being LOW and all devices being active-HIGH.
  */
 int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
-			       struct irq_phys_map *map, bool level)
+			       int virt_irq, bool level)
 {
 	int ret;
 
@@ -1687,7 +1686,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 	if (ret)
 		return ret;
 
-	return vgic_update_irq_pending(kvm, cpuid, map, map->virt_irq, level);
+	return vgic_update_irq_pending(kvm, cpuid, virt_irq, level);
 }
 
 static irqreturn_t vgic_maintenance_handler(int irq, void *data)
@@ -1818,7 +1817,8 @@ static void vgic_free_phys_irq_map_rcu(struct rcu_head *rcu)
  *
  * Remove an existing mapping between virtual and physical interrupts.
  */
-int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map)
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
+			    int virt_irq)
 {
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct irq_phys_map_entry *entry;
-- 
2.7.3


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

* [RFC PATCH 03/45] KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Adapt the interface between the virtualized arch timer and the
emulated VGIC to avoid the phys_map when possible.
This prepares the arch timer to go with both the existing VGIC
implementation and the new version later without too many code
changes.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h    |  7 ++++---
 virt/kvm/arm/arch_timer.c | 11 +++++------
 virt/kvm/arm/vgic.c       | 18 +++++++++---------
 3 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 2b89e27..7656a46 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -345,13 +345,14 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
 			bool level);
 int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
-			       struct irq_phys_map *map, bool level);
+			       int virt_irq, bool level);
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 					   int virt_irq, int irq);
-int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
-bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
+			    int virt_irq);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, int virt_irq);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index a9ad4fe..74e3d4b 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -137,10 +137,10 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
 
 	timer->active_cleared_last = false;
 	timer->irq.level = new_level;
-	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->map->virt_irq,
+	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq,
 				   timer->irq.level);
 	ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
-					 timer->map,
+					 timer->irq.irq,
 					 timer->irq.level);
 	WARN_ON(ret);
 }
@@ -246,7 +246,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	* to ensure that hardware interrupts from the timer triggers a guest
 	* exit.
 	*/
-	if (timer->irq.level || kvm_vgic_map_is_active(vcpu, timer->map))
+	if (timer->irq.level || kvm_vgic_map_is_active(vcpu, timer->irq.irq))
 		phys_active = true;
 	else
 		phys_active = false;
@@ -274,7 +274,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	if (timer->active_cleared_last && !phys_active)
 		return;
 
-	ret = irq_set_irqchip_state(timer->map->irq,
+	ret = irq_set_irqchip_state(host_vtimer_irq,
 				    IRQCHIP_STATE_ACTIVE,
 				    phys_active);
 	WARN_ON(ret);
@@ -476,8 +476,7 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 
 	timer_disarm(timer);
-	if (timer->map)
-		kvm_vgic_unmap_phys_irq(vcpu, timer->map);
+	kvm_vgic_unmap_phys_irq(vcpu, timer->map, timer->irq.irq);
 }
 
 void kvm_timer_enable(struct kvm *kvm)
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00429b3..079b0a7 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1103,18 +1103,18 @@ static bool dist_active_irq(struct kvm_vcpu *vcpu)
 	return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu);
 }
 
-bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map)
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, int virt_irq)
 {
 	int i;
 
 	for (i = 0; i < vcpu->arch.vgic_cpu.nr_lr; i++) {
 		struct vgic_lr vlr = vgic_get_lr(vcpu, i);
 
-		if (vlr.irq == map->virt_irq && vlr.state & LR_STATE_ACTIVE)
+		if (vlr.irq == virt_irq && vlr.state & LR_STATE_ACTIVE)
 			return true;
 	}
 
-	return vgic_irq_is_active(vcpu, map->virt_irq);
+	return vgic_irq_is_active(vcpu, virt_irq);
 }
 
 /*
@@ -1522,7 +1522,6 @@ static int vgic_validate_injection(struct kvm_vcpu *vcpu, int irq, int level)
 }
 
 static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
-				   struct irq_phys_map *map,
 				   unsigned int irq_num, bool level)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
@@ -1661,14 +1660,14 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
 	if (map)
 		return -EINVAL;
 
-	return vgic_update_irq_pending(kvm, cpuid, NULL, irq_num, level);
+	return vgic_update_irq_pending(kvm, cpuid, irq_num, level);
 }
 
 /**
  * kvm_vgic_inject_mapped_irq - Inject a physically mapped IRQ to the vgic
  * @kvm:     The VM structure pointer
  * @cpuid:   The CPU for PPIs
- * @map:     Pointer to a irq_phys_map structure describing the mapping
+ * @virt_irq: The virtual IRQ to be injected
  * @level:   Edge-triggered:  true:  to trigger the interrupt
  *			      false: to ignore the call
  *	     Level-sensitive  true:  raise the input signal
@@ -1679,7 +1678,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
  * being HIGH and 0 being LOW and all devices being active-HIGH.
  */
 int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
-			       struct irq_phys_map *map, bool level)
+			       int virt_irq, bool level)
 {
 	int ret;
 
@@ -1687,7 +1686,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 	if (ret)
 		return ret;
 
-	return vgic_update_irq_pending(kvm, cpuid, map, map->virt_irq, level);
+	return vgic_update_irq_pending(kvm, cpuid, virt_irq, level);
 }
 
 static irqreturn_t vgic_maintenance_handler(int irq, void *data)
@@ -1818,7 +1817,8 @@ static void vgic_free_phys_irq_map_rcu(struct rcu_head *rcu)
  *
  * Remove an existing mapping between virtual and physical interrupts.
  */
-int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map)
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
+			    int virt_irq)
 {
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct irq_phys_map_entry *entry;
-- 
2.7.3

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

* [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Christoffer Dall <christoffer.dall@linaro.org>

Add a new header file for the new and improved GIC implementation.
The big change is that we now have a struct vgic_irq per IRQ instead
of spreading all the information over various bitmaps.

We include this new header conditionally from within the old header
file for the time being to avoid touching all the users.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h  |   5 ++
 include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 203 insertions(+)
 create mode 100644 include/kvm/vgic/vgic.h

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 7656a46..db289a2 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -19,6 +19,10 @@
 #ifndef __ASM_ARM_KVM_VGIC_H
 #define __ASM_ARM_KVM_VGIC_H
 
+#ifdef CONFIG_KVM_NEW_VGIC
+#include <kvm/vgic/vgic.h>
+#else
+
 #include <linux/kernel.h>
 #include <linux/kvm.h>
 #include <linux/irqreturn.h>
@@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
 }
 #endif
 
+#endif	/* old VGIC include */
 #endif
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
new file mode 100644
index 0000000..659f8b1
--- /dev/null
+++ b/include/kvm/vgic/vgic.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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 __ASM_ARM_KVM_VGIC_VGIC_H
+#define __ASM_ARM_KVM_VGIC_VGIC_H
+
+#include <linux/kernel.h>
+#include <linux/kvm.h>
+#include <linux/irqreturn.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <kvm/iodev.h>
+
+#define VGIC_V3_MAX_CPUS	255
+#define VGIC_V2_MAX_CPUS	8
+#define VGIC_NR_IRQS_LEGACY     256
+#define VGIC_NR_SGIS		16
+#define VGIC_NR_PPIS		16
+#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
+#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
+#define VGIC_MAX_SPI		1019
+#define VGIC_MAX_RESERVED	1023
+#define VGIC_MIN_LPI		8192
+
+enum vgic_type {
+	VGIC_V2,		/* Good ol' GICv2 */
+	VGIC_V3,		/* New fancy GICv3 */
+};
+
+/* same for all guests, as depending only on the _host's_ GIC model */
+struct vgic_global {
+	/* type of the host GIC */
+	enum vgic_type		type;
+
+	/* Physical address of vgic virtual cpu interface */
+	phys_addr_t		vcpu_base;
+
+	/* virtual control interface mapping */
+	void __iomem		*vctrl_base;
+
+	/* Number of implemented list registers */
+	int			nr_lr;
+
+	/* Maintenance IRQ number */
+	unsigned int		maint_irq;
+
+	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
+	int			max_gic_vcpus;
+
+	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
+	bool			can_emulate_gicv2;
+};
+
+extern struct vgic_global kvm_vgic_global_state;
+
+#define VGIC_V2_MAX_LRS		(1 << 6)
+#define VGIC_V3_MAX_LRS		16
+#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
+
+enum vgic_irq_config {
+	VGIC_CONFIG_EDGE = 0,
+	VGIC_CONFIG_LEVEL
+};
+
+struct vgic_irq {
+	spinlock_t irq_lock;		/* Protects the content of the struct */
+	struct list_head ap_list;
+
+	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
+					 * SPIs and LPIs: The VCPU whose ap_list
+					 * on which this is queued.
+					 */
+
+	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
+					 * be send to, as a result of the
+					 * targets reg (v2) or the
+					 * affinity reg (v3).
+					 */
+
+	u32 intid;			/* Guest visible INTID */
+	bool pending;
+	bool line_level;		/* Level only */
+	bool soft_pending;		/* Level only */
+	bool active;			/* not used for LPIs */
+	bool enabled;
+	bool hw;			/* Tied to HW IRQ */
+	u32 hwintid;			/* HW INTID number */
+	union {
+		u8 targets;			/* GICv2 target VCPUs mask */
+		u32 mpidr;			/* GICv3 target VCPU */
+	};
+	u8 source;			/* GICv2 SGIs only */
+	u8 priority;
+	enum vgic_irq_config config;	/* Level or edge */
+};
+
+struct vgic_dist {
+	bool			in_kernel;
+	bool			ready;
+
+	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
+	u32			vgic_model;
+
+	int			nr_spis;
+
+	/* TODO: Consider moving to global state */
+	/* Virtual control interface mapping */
+	void __iomem		*vctrl_base;
+
+	/* base addresses in guest physical address space: */
+	gpa_t			vgic_dist_base;		/* distributor */
+	union {
+		/* either a GICv2 CPU interface */
+		gpa_t			vgic_cpu_base;
+		/* or a number of GICv3 redistributor regions */
+		gpa_t			vgic_redist_base;
+	};
+
+	/* distributor enabled */
+	u32			enabled;
+
+	struct vgic_irq		*spis;
+};
+
+struct vgic_v2_cpu_if {
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_misr;	/* Saved only */
+	u64		vgic_eisr;	/* Saved only */
+	u64		vgic_elrsr;	/* Saved only */
+	u32		vgic_apr;
+	u32		vgic_lr[VGIC_V2_MAX_LRS];
+};
+
+struct vgic_v3_cpu_if {
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_sre;	/* Restored only, change ignored */
+	u32		vgic_misr;	/* Saved only */
+	u32		vgic_eisr;	/* Saved only */
+	u32		vgic_elrsr;	/* Saved only */
+	u32		vgic_ap0r[4];
+	u32		vgic_ap1r[4];
+	u64		vgic_lr[VGIC_V3_MAX_LRS];
+#endif
+};
+
+struct vgic_cpu {
+	/* CPU vif control registers for world switch */
+	union {
+		struct vgic_v2_cpu_if	vgic_v2;
+		struct vgic_v3_cpu_if	vgic_v3;
+	};
+
+	/* TODO: Move nr_lr to a global state */
+	/* Number of list registers on this CPU */
+	int		nr_lr;
+
+	unsigned int used_lrs;
+	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
+
+	spinlock_t ap_list_lock;	/* Protects the ap_list */
+
+	/* list of IRQs for this VCPU to consider */
+	struct list_head ap_list_head;
+};
+
+#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
+#define vgic_initialized(k)	(false)
+#define vgic_ready(k)		((k)->arch.vgic.ready)
+#define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
+
+/**
+ * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
+ *
+ * The host's GIC naturally limits the maximum amount of VCPUs a guest
+ * can use.
+ */
+static inline int kvm_vgic_get_max_vcpus(void)
+{
+	return kvm_vgic_global_state.max_gic_vcpus;
+}
+
+#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
-- 
2.7.3

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

* [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Christoffer Dall <christoffer.dall@linaro.org>

Add a new header file for the new and improved GIC implementation.
The big change is that we now have a struct vgic_irq per IRQ instead
of spreading all the information over various bitmaps.

We include this new header conditionally from within the old header
file for the time being to avoid touching all the users.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h  |   5 ++
 include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 203 insertions(+)
 create mode 100644 include/kvm/vgic/vgic.h

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 7656a46..db289a2 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -19,6 +19,10 @@
 #ifndef __ASM_ARM_KVM_VGIC_H
 #define __ASM_ARM_KVM_VGIC_H
 
+#ifdef CONFIG_KVM_NEW_VGIC
+#include <kvm/vgic/vgic.h>
+#else
+
 #include <linux/kernel.h>
 #include <linux/kvm.h>
 #include <linux/irqreturn.h>
@@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
 }
 #endif
 
+#endif	/* old VGIC include */
 #endif
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
new file mode 100644
index 0000000..659f8b1
--- /dev/null
+++ b/include/kvm/vgic/vgic.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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 __ASM_ARM_KVM_VGIC_VGIC_H
+#define __ASM_ARM_KVM_VGIC_VGIC_H
+
+#include <linux/kernel.h>
+#include <linux/kvm.h>
+#include <linux/irqreturn.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <kvm/iodev.h>
+
+#define VGIC_V3_MAX_CPUS	255
+#define VGIC_V2_MAX_CPUS	8
+#define VGIC_NR_IRQS_LEGACY     256
+#define VGIC_NR_SGIS		16
+#define VGIC_NR_PPIS		16
+#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
+#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
+#define VGIC_MAX_SPI		1019
+#define VGIC_MAX_RESERVED	1023
+#define VGIC_MIN_LPI		8192
+
+enum vgic_type {
+	VGIC_V2,		/* Good ol' GICv2 */
+	VGIC_V3,		/* New fancy GICv3 */
+};
+
+/* same for all guests, as depending only on the _host's_ GIC model */
+struct vgic_global {
+	/* type of the host GIC */
+	enum vgic_type		type;
+
+	/* Physical address of vgic virtual cpu interface */
+	phys_addr_t		vcpu_base;
+
+	/* virtual control interface mapping */
+	void __iomem		*vctrl_base;
+
+	/* Number of implemented list registers */
+	int			nr_lr;
+
+	/* Maintenance IRQ number */
+	unsigned int		maint_irq;
+
+	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
+	int			max_gic_vcpus;
+
+	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
+	bool			can_emulate_gicv2;
+};
+
+extern struct vgic_global kvm_vgic_global_state;
+
+#define VGIC_V2_MAX_LRS		(1 << 6)
+#define VGIC_V3_MAX_LRS		16
+#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
+
+enum vgic_irq_config {
+	VGIC_CONFIG_EDGE = 0,
+	VGIC_CONFIG_LEVEL
+};
+
+struct vgic_irq {
+	spinlock_t irq_lock;		/* Protects the content of the struct */
+	struct list_head ap_list;
+
+	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
+					 * SPIs and LPIs: The VCPU whose ap_list
+					 * on which this is queued.
+					 */
+
+	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
+					 * be send to, as a result of the
+					 * targets reg (v2) or the
+					 * affinity reg (v3).
+					 */
+
+	u32 intid;			/* Guest visible INTID */
+	bool pending;
+	bool line_level;		/* Level only */
+	bool soft_pending;		/* Level only */
+	bool active;			/* not used for LPIs */
+	bool enabled;
+	bool hw;			/* Tied to HW IRQ */
+	u32 hwintid;			/* HW INTID number */
+	union {
+		u8 targets;			/* GICv2 target VCPUs mask */
+		u32 mpidr;			/* GICv3 target VCPU */
+	};
+	u8 source;			/* GICv2 SGIs only */
+	u8 priority;
+	enum vgic_irq_config config;	/* Level or edge */
+};
+
+struct vgic_dist {
+	bool			in_kernel;
+	bool			ready;
+
+	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
+	u32			vgic_model;
+
+	int			nr_spis;
+
+	/* TODO: Consider moving to global state */
+	/* Virtual control interface mapping */
+	void __iomem		*vctrl_base;
+
+	/* base addresses in guest physical address space: */
+	gpa_t			vgic_dist_base;		/* distributor */
+	union {
+		/* either a GICv2 CPU interface */
+		gpa_t			vgic_cpu_base;
+		/* or a number of GICv3 redistributor regions */
+		gpa_t			vgic_redist_base;
+	};
+
+	/* distributor enabled */
+	u32			enabled;
+
+	struct vgic_irq		*spis;
+};
+
+struct vgic_v2_cpu_if {
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_misr;	/* Saved only */
+	u64		vgic_eisr;	/* Saved only */
+	u64		vgic_elrsr;	/* Saved only */
+	u32		vgic_apr;
+	u32		vgic_lr[VGIC_V2_MAX_LRS];
+};
+
+struct vgic_v3_cpu_if {
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_sre;	/* Restored only, change ignored */
+	u32		vgic_misr;	/* Saved only */
+	u32		vgic_eisr;	/* Saved only */
+	u32		vgic_elrsr;	/* Saved only */
+	u32		vgic_ap0r[4];
+	u32		vgic_ap1r[4];
+	u64		vgic_lr[VGIC_V3_MAX_LRS];
+#endif
+};
+
+struct vgic_cpu {
+	/* CPU vif control registers for world switch */
+	union {
+		struct vgic_v2_cpu_if	vgic_v2;
+		struct vgic_v3_cpu_if	vgic_v3;
+	};
+
+	/* TODO: Move nr_lr to a global state */
+	/* Number of list registers on this CPU */
+	int		nr_lr;
+
+	unsigned int used_lrs;
+	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
+
+	spinlock_t ap_list_lock;	/* Protects the ap_list */
+
+	/* list of IRQs for this VCPU to consider */
+	struct list_head ap_list_head;
+};
+
+#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
+#define vgic_initialized(k)	(false)
+#define vgic_ready(k)		((k)->arch.vgic.ready)
+#define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
+
+/**
+ * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
+ *
+ * The host's GIC naturally limits the maximum amount of VCPUs a guest
+ * can use.
+ */
+static inline int kvm_vgic_get_max_vcpus(void)
+{
+	return kvm_vgic_global_state.max_gic_vcpus;
+}
+
+#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
-- 
2.7.3

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

* [RFC PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: kvmarm, kvm, linux-arm-kernel

From: Christoffer Dall <christoffer.dall@linaro.org>

The new VGIC implementation centers around a struct vgic_irq instance
per virtual IRQ.
Provide a function to retrieve the right instance for a given IRQ
number and (in case of private interrupts) the right VCPU.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.c | 41 +++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h | 22 ++++++++++++++++++++++
 2 files changed, 63 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic.c
 create mode 100644 virt/kvm/arm/vgic/vgic.h

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
new file mode 100644
index 0000000..8e34916
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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/kvm.h>
+#include <linux/kvm_host.h>
+
+#include "vgic.h"
+
+struct vgic_global kvm_vgic_global_state;
+
+struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
+			      u32 intid)
+{
+	/* SGIs and PPIs */
+	if (intid <= VGIC_MAX_PRIVATE)
+		return &vcpu->arch.vgic_cpu.private_irqs[intid];
+
+	/* SPIs */
+	if (intid <= VGIC_MAX_SPI)
+		return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
+
+	/* LPIs are not yet covered */
+	if (intid >= VGIC_MIN_LPI)
+		return NULL;
+
+	WARN(1, "Looking up struct vgic_irq for reserved INTID");
+	return NULL;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
new file mode 100644
index 0000000..61b8d22
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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_ARM_VGIC_NEW_H__
+#define __KVM_ARM_VGIC_NEW_H__
+
+struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
+			      u32 intid);
+
+#endif
-- 
2.7.3


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

* [RFC PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Christoffer Dall <christoffer.dall@linaro.org>

The new VGIC implementation centers around a struct vgic_irq instance
per virtual IRQ.
Provide a function to retrieve the right instance for a given IRQ
number and (in case of private interrupts) the right VCPU.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.c | 41 +++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h | 22 ++++++++++++++++++++++
 2 files changed, 63 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic.c
 create mode 100644 virt/kvm/arm/vgic/vgic.h

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
new file mode 100644
index 0000000..8e34916
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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/kvm.h>
+#include <linux/kvm_host.h>
+
+#include "vgic.h"
+
+struct vgic_global kvm_vgic_global_state;
+
+struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
+			      u32 intid)
+{
+	/* SGIs and PPIs */
+	if (intid <= VGIC_MAX_PRIVATE)
+		return &vcpu->arch.vgic_cpu.private_irqs[intid];
+
+	/* SPIs */
+	if (intid <= VGIC_MAX_SPI)
+		return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
+
+	/* LPIs are not yet covered */
+	if (intid >= VGIC_MIN_LPI)
+		return NULL;
+
+	WARN(1, "Looking up struct vgic_irq for reserved INTID");
+	return NULL;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
new file mode 100644
index 0000000..61b8d22
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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_ARM_VGIC_NEW_H__
+#define __KVM_ARM_VGIC_NEW_H__
+
+struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
+			      u32 intid);
+
+#endif
-- 
2.7.3

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

* [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Christoffer Dall <christoffer.dall@linaro.org>

Provide a vgic_queue_irq() function which decides whether a given
IRQ needs to be queued to a VCPU's ap_list.
This should be called whenever an IRQ became pending or got enabled,
either as a result of userspace injection, from in-kernel emulated
devices like the architected timer or from MMIO accesses to the
distributor emulation.
Also provides the necessary functions to allow userland to inject an
IRQ to a guest.
[Andre: refactor out vgic_queue_irq()]

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h  |   3 +
 virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h |   1 +
 3 files changed, 185 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 659f8b1..f32b284 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -178,6 +178,9 @@ struct vgic_cpu {
 	struct list_head ap_list_head;
 };
 
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			bool level);
+
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(false)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 8e34916..a95aabc 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -19,8 +19,25 @@
 
 #include "vgic.h"
 
+#define CREATE_TRACE_POINTS
+#include "../trace.h"
+
 struct vgic_global kvm_vgic_global_state;
 
+/*
+ * Locking order is always:
+ *   vgic_cpu->ap_list_lock
+ *     vgic_irq->irq_lock
+ *
+ * (that is, always take the ap_list_lock before the struct vgic_irq lock).
+ *
+ * When taking more than one ap_list_lock at the same time, always take the
+ * lowest numbered VCPU's ap_list_lock first, so:
+ *   vcpuX->vcpu_id < vcpuY->vcpu_id:
+ *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
+ *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
+ */
+
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid)
 {
@@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 	WARN(1, "Looking up struct vgic_irq for reserved INTID");
 	return NULL;
 }
+
+/**
+ * kvm_vgic_target_oracle - compute the target vcpu for an irq
+ *
+ * @irq:	The irq to route. Must be already locked.
+ *
+ * Based on the current state of the interrupt (enabled, pending,
+ * active, vcpu and target_vcpu), compute the next vcpu this should be
+ * given to. Return NULL if this shouldn't be injected at all.
+ */
+static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
+{
+	/* If the interrupt is active, it must stay on the current vcpu */
+	if (irq->active)
+		return irq->vcpu;
+
+	/* If enabled and pending, it can migrate to a new one */
+	if (irq->enabled && irq->pending)
+		return irq->target_vcpu;
+
+	/* Otherwise, it is considered idle */
+	return NULL;
+}
+
+/*
+ * Only valid injection if changing level for level-triggered IRQs or for a
+ * rising edge.
+ */
+static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
+{
+	switch (irq->config) {
+	case VGIC_CONFIG_LEVEL:
+		return irq->line_level != level;
+	case VGIC_CONFIG_EDGE:
+		return level;
+	default:
+		BUG();
+	}
+}
+
+/*
+ * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
+ * Do the queuing if necessary, taking the right locks in the right order.
+ * Returns true when the IRQ was queued, false otherwise.
+ *
+ * Needs to be entered with the IRQ lock already held, but will return
+ * with all locks dropped.
+ */
+bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)
+{
+	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);
+
+	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
+		/*
+		 * If this IRQ is already on a VCPU's ap_list, then it
+		 * cannot be moved or modified and there is no more work for
+		 * us to do.
+		 *
+		 * Otherwise, if the irq is not pending and enabled, it does
+		 * not need to be inserted into an ap_list and there is also
+		 * no more work for us to do.
+		 */
+		spin_unlock(&irq->irq_lock);
+		return false;
+	}
+
+	/*
+	 * We must unlock the irq lock to take the ap_list_lock where
+	 * we are going to insert this new pending interrupt.
+	 */
+	spin_unlock(&irq->irq_lock);
+
+	/* someone can do stuff here, which we re-check below */
+retry:
+	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+	spin_lock(&irq->irq_lock);
+
+	/*
+	 * Did something change behind our backs?
+	 *
+	 * There are two cases:
+	 * 1) The irq became pending or active behind our backs and/or
+	 *    the irq->vcpu field was set correspondingly when putting
+	 *    the irq on an ap_list. Then drop the locks and return.
+	 * 2) Someone changed the affinity on this irq behind our
+	 *    backs and we are now holding the wrong ap_list_lock.
+	 *    Then drop the locks and try the new VCPU.
+	 */
+	if (irq->vcpu || !(irq->pending && irq->enabled)) {
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+		return false;
+	}
+
+	if (irq->target_vcpu != vcpu) {
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+		vcpu = irq->target_vcpu;
+		goto retry;
+	}
+
+	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
+	irq->vcpu = vcpu;
+
+	spin_unlock(&irq->irq_lock);
+	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+	kvm_vcpu_kick(vcpu);
+
+	return true;
+}
+
+static void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
+				    u32 intid, bool level)
+{
+	struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
+
+	trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
+
+	BUG_ON(in_interrupt());
+
+	spin_lock(&irq->irq_lock);
+
+	if (!vgic_validate_injection(irq, level)) {
+		/* Nothing to see here, move along... */
+		spin_unlock(&irq->irq_lock);
+		return;
+	}
+
+	if (irq->config == VGIC_CONFIG_LEVEL) {
+		irq->line_level = level;
+		irq->pending = level || irq->soft_pending;
+	} else {
+		irq->pending = true;
+	}
+
+	vgic_queue_irq(kvm, irq);
+}
+
+/**
+ * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
+ * @kvm:     The VM structure pointer
+ * @cpuid:   The CPU for PPIs
+ * @intid:   The INTID to inject a new state to.
+ *           must not be mapped to a HW interrupt.
+ * @level:   Edge-triggered:  true:  to trigger the interrupt
+ *			      false: to ignore the call
+ *	     Level-sensitive  true:  raise the input signal
+ *			      false: lower the input signal
+ *
+ * The GIC is not concerned with devices being active-LOW or active-HIGH for
+ * level-sensitive interrupts.  You can think of the level parameter as 1
+ * being HIGH and 0 being LOW and all devices being active-HIGH.
+ */
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			bool level)
+{
+	struct kvm_vcpu *vcpu;
+
+	vcpu = kvm_get_vcpu(kvm, cpuid);
+	vgic_update_irq_pending(kvm, vcpu, intid, level);
+	return 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 61b8d22..e9f4aa6 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -18,5 +18,6 @@
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
+bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
 
 #endif
-- 
2.7.3

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

* [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Christoffer Dall <christoffer.dall@linaro.org>

Provide a vgic_queue_irq() function which decides whether a given
IRQ needs to be queued to a VCPU's ap_list.
This should be called whenever an IRQ became pending or got enabled,
either as a result of userspace injection, from in-kernel emulated
devices like the architected timer or from MMIO accesses to the
distributor emulation.
Also provides the necessary functions to allow userland to inject an
IRQ to a guest.
[Andre: refactor out vgic_queue_irq()]

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h  |   3 +
 virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h |   1 +
 3 files changed, 185 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 659f8b1..f32b284 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -178,6 +178,9 @@ struct vgic_cpu {
 	struct list_head ap_list_head;
 };
 
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			bool level);
+
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(false)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 8e34916..a95aabc 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -19,8 +19,25 @@
 
 #include "vgic.h"
 
+#define CREATE_TRACE_POINTS
+#include "../trace.h"
+
 struct vgic_global kvm_vgic_global_state;
 
+/*
+ * Locking order is always:
+ *   vgic_cpu->ap_list_lock
+ *     vgic_irq->irq_lock
+ *
+ * (that is, always take the ap_list_lock before the struct vgic_irq lock).
+ *
+ * When taking more than one ap_list_lock at the same time, always take the
+ * lowest numbered VCPU's ap_list_lock first, so:
+ *   vcpuX->vcpu_id < vcpuY->vcpu_id:
+ *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
+ *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
+ */
+
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid)
 {
@@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 	WARN(1, "Looking up struct vgic_irq for reserved INTID");
 	return NULL;
 }
+
+/**
+ * kvm_vgic_target_oracle - compute the target vcpu for an irq
+ *
+ * @irq:	The irq to route. Must be already locked.
+ *
+ * Based on the current state of the interrupt (enabled, pending,
+ * active, vcpu and target_vcpu), compute the next vcpu this should be
+ * given to. Return NULL if this shouldn't be injected at all.
+ */
+static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
+{
+	/* If the interrupt is active, it must stay on the current vcpu */
+	if (irq->active)
+		return irq->vcpu;
+
+	/* If enabled and pending, it can migrate to a new one */
+	if (irq->enabled && irq->pending)
+		return irq->target_vcpu;
+
+	/* Otherwise, it is considered idle */
+	return NULL;
+}
+
+/*
+ * Only valid injection if changing level for level-triggered IRQs or for a
+ * rising edge.
+ */
+static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
+{
+	switch (irq->config) {
+	case VGIC_CONFIG_LEVEL:
+		return irq->line_level != level;
+	case VGIC_CONFIG_EDGE:
+		return level;
+	default:
+		BUG();
+	}
+}
+
+/*
+ * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
+ * Do the queuing if necessary, taking the right locks in the right order.
+ * Returns true when the IRQ was queued, false otherwise.
+ *
+ * Needs to be entered with the IRQ lock already held, but will return
+ * with all locks dropped.
+ */
+bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)
+{
+	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);
+
+	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
+		/*
+		 * If this IRQ is already on a VCPU's ap_list, then it
+		 * cannot be moved or modified and there is no more work for
+		 * us to do.
+		 *
+		 * Otherwise, if the irq is not pending and enabled, it does
+		 * not need to be inserted into an ap_list and there is also
+		 * no more work for us to do.
+		 */
+		spin_unlock(&irq->irq_lock);
+		return false;
+	}
+
+	/*
+	 * We must unlock the irq lock to take the ap_list_lock where
+	 * we are going to insert this new pending interrupt.
+	 */
+	spin_unlock(&irq->irq_lock);
+
+	/* someone can do stuff here, which we re-check below */
+retry:
+	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+	spin_lock(&irq->irq_lock);
+
+	/*
+	 * Did something change behind our backs?
+	 *
+	 * There are two cases:
+	 * 1) The irq became pending or active behind our backs and/or
+	 *    the irq->vcpu field was set correspondingly when putting
+	 *    the irq on an ap_list. Then drop the locks and return.
+	 * 2) Someone changed the affinity on this irq behind our
+	 *    backs and we are now holding the wrong ap_list_lock.
+	 *    Then drop the locks and try the new VCPU.
+	 */
+	if (irq->vcpu || !(irq->pending && irq->enabled)) {
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+		return false;
+	}
+
+	if (irq->target_vcpu != vcpu) {
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+		vcpu = irq->target_vcpu;
+		goto retry;
+	}
+
+	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
+	irq->vcpu = vcpu;
+
+	spin_unlock(&irq->irq_lock);
+	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+	kvm_vcpu_kick(vcpu);
+
+	return true;
+}
+
+static void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
+				    u32 intid, bool level)
+{
+	struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
+
+	trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
+
+	BUG_ON(in_interrupt());
+
+	spin_lock(&irq->irq_lock);
+
+	if (!vgic_validate_injection(irq, level)) {
+		/* Nothing to see here, move along... */
+		spin_unlock(&irq->irq_lock);
+		return;
+	}
+
+	if (irq->config == VGIC_CONFIG_LEVEL) {
+		irq->line_level = level;
+		irq->pending = level || irq->soft_pending;
+	} else {
+		irq->pending = true;
+	}
+
+	vgic_queue_irq(kvm, irq);
+}
+
+/**
+ * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
+ * @kvm:     The VM structure pointer
+ * @cpuid:   The CPU for PPIs
+ * @intid:   The INTID to inject a new state to.
+ *           must not be mapped to a HW interrupt.
+ * @level:   Edge-triggered:  true:  to trigger the interrupt
+ *			      false: to ignore the call
+ *	     Level-sensitive  true:  raise the input signal
+ *			      false: lower the input signal
+ *
+ * The GIC is not concerned with devices being active-LOW or active-HIGH for
+ * level-sensitive interrupts.  You can think of the level parameter as 1
+ * being HIGH and 0 being LOW and all devices being active-HIGH.
+ */
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			bool level)
+{
+	struct kvm_vcpu *vcpu;
+
+	vcpu = kvm_get_vcpu(kvm, cpuid);
+	vgic_update_irq_pending(kvm, vcpu, intid, level);
+	return 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 61b8d22..e9f4aa6 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -18,5 +18,6 @@
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
+bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
 
 #endif
-- 
2.7.3

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

* [RFC PATCH 07/45] KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Christoffer Dall <christoffer.dall@linaro.org>

Introduce vgic-v2.c to contain GICv2 specific functions.
Add vgic_v2_irq_change_affinity() to change the target VCPU of a
particular interrupt.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <marc.zyngier@arm.com>
---
 virt/kvm/arm/vgic/vgic-v2.c | 40 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h    |  2 ++
 2 files changed, 42 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-v2.c

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
new file mode 100644
index 0000000..0bf6f27
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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/kvm.h>
+#include <linux/kvm_host.h>
+
+#include "vgic.h"
+
+void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct vgic_irq *irq;
+	int target;
+
+	BUG_ON(intid <= VGIC_MAX_PRIVATE);
+	BUG_ON(dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2);
+
+	irq = vgic_get_irq(kvm, NULL, intid);
+
+	spin_lock(&irq->irq_lock);
+	irq->targets = new_targets;
+
+	target = ffs(irq->targets);
+	target = target ? (target - 1) : 0;
+	irq->target_vcpu = kvm_get_vcpu(kvm, target);
+	spin_unlock(&irq->irq_lock);
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index e9f4aa6..b2faf00 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -20,4 +20,6 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
 
+void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
+
 #endif
-- 
2.7.3

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

* [RFC PATCH 07/45] KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Christoffer Dall <christoffer.dall@linaro.org>

Introduce vgic-v2.c to contain GICv2 specific functions.
Add vgic_v2_irq_change_affinity() to change the target VCPU of a
particular interrupt.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <marc.zyngier@arm.com>
---
 virt/kvm/arm/vgic/vgic-v2.c | 40 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h    |  2 ++
 2 files changed, 42 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-v2.c

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
new file mode 100644
index 0000000..0bf6f27
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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/kvm.h>
+#include <linux/kvm_host.h>
+
+#include "vgic.h"
+
+void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct vgic_irq *irq;
+	int target;
+
+	BUG_ON(intid <= VGIC_MAX_PRIVATE);
+	BUG_ON(dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2);
+
+	irq = vgic_get_irq(kvm, NULL, intid);
+
+	spin_lock(&irq->irq_lock);
+	irq->targets = new_targets;
+
+	target = ffs(irq->targets);
+	target = target ? (target - 1) : 0;
+	irq->target_vcpu = kvm_get_vcpu(kvm, target);
+	spin_unlock(&irq->irq_lock);
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index e9f4aa6..b2faf00 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -20,4 +20,6 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
 
+void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
+
 #endif
-- 
2.7.3

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

* [RFC PATCH 08/45] KVM: arm/arm64: vgic-new: Add IRQ sorting
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Christoffer Dall <christoffer.dall@linaro.org>

Adds the sorting function to cover the case where you have more IRQs
to consider than you have LRs. We now consider priorities.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index a95aabc..29c753e 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -16,6 +16,7 @@
 
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <linux/list_sort.h>
 
 #include "vgic.h"
 
@@ -81,6 +82,58 @@ static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
 }
 
 /*
+ * The order of items in the ap_lists defines how we'll pack things in LRs as
+ * well, the first items in the list being the first things populated in the
+ * LRs.
+ *
+ * A hard rule is that active interrupts can never be pushed out of the LRs
+ * (and therefore take priority) since we cannot reliably trap on deactivation
+ * of IRQs and therefore they have to be present in the LRs.
+ *
+ * Otherwise things should be sorted by the priority field and the GIC
+ * hardware support will take care of preemption of priority groups etc.
+ *
+ * Return negative if "a" sorts before "b", 0 to preserve order, and positive
+ * to sort "b" before "a".
+ */
+static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+	struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
+	struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
+	bool penda, pendb;
+	int ret;
+
+	spin_lock(&irqa->irq_lock);
+	spin_lock(&irqb->irq_lock);
+
+	if (irqa->active || irqb->active) {
+		ret = (int)irqb->active - (int)irqa->active;
+		goto out;
+	}
+
+	penda = irqa->enabled && irqa->pending;
+	pendb = irqb->enabled && irqb->pending;
+
+	if (!penda || !pendb) {
+		ret = (int)pendb - (int)penda;
+		goto out;
+	}
+
+	/* Both pending and enabled, sort by priority */
+	ret = irqa->priority - irqb->priority;
+out:
+	spin_unlock(&irqb->irq_lock);
+	spin_unlock(&irqa->irq_lock);
+	return ret;
+}
+
+/* Must be called with the ap_list_lock held */
+static void vgic_sort_ap_list(struct kvm_vcpu *vcpu)
+{
+	list_sort(NULL, &vcpu->arch.vgic_cpu.ap_list_head, vgic_irq_cmp);
+}
+
+/*
  * Only valid injection if changing level for level-triggered IRQs or for a
  * rising edge.
  */
-- 
2.7.3

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

* [RFC PATCH 08/45] KVM: arm/arm64: vgic-new: Add IRQ sorting
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Christoffer Dall <christoffer.dall@linaro.org>

Adds the sorting function to cover the case where you have more IRQs
to consider than you have LRs. We now consider priorities.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index a95aabc..29c753e 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -16,6 +16,7 @@
 
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <linux/list_sort.h>
 
 #include "vgic.h"
 
@@ -81,6 +82,58 @@ static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
 }
 
 /*
+ * The order of items in the ap_lists defines how we'll pack things in LRs as
+ * well, the first items in the list being the first things populated in the
+ * LRs.
+ *
+ * A hard rule is that active interrupts can never be pushed out of the LRs
+ * (and therefore take priority) since we cannot reliably trap on deactivation
+ * of IRQs and therefore they have to be present in the LRs.
+ *
+ * Otherwise things should be sorted by the priority field and the GIC
+ * hardware support will take care of preemption of priority groups etc.
+ *
+ * Return negative if "a" sorts before "b", 0 to preserve order, and positive
+ * to sort "b" before "a".
+ */
+static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+	struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
+	struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
+	bool penda, pendb;
+	int ret;
+
+	spin_lock(&irqa->irq_lock);
+	spin_lock(&irqb->irq_lock);
+
+	if (irqa->active || irqb->active) {
+		ret = (int)irqb->active - (int)irqa->active;
+		goto out;
+	}
+
+	penda = irqa->enabled && irqa->pending;
+	pendb = irqb->enabled && irqb->pending;
+
+	if (!penda || !pendb) {
+		ret = (int)pendb - (int)penda;
+		goto out;
+	}
+
+	/* Both pending and enabled, sort by priority */
+	ret = irqa->priority - irqb->priority;
+out:
+	spin_unlock(&irqb->irq_lock);
+	spin_unlock(&irqa->irq_lock);
+	return ret;
+}
+
+/* Must be called with the ap_list_lock held */
+static void vgic_sort_ap_list(struct kvm_vcpu *vcpu)
+{
+	list_sort(NULL, &vcpu->arch.vgic_cpu.ap_list_head, vgic_irq_cmp);
+}
+
+/*
  * Only valid injection if changing level for level-triggered IRQs or for a
  * rising edge.
  */
-- 
2.7.3

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

* [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

Implement the functionality for syncing IRQs between our emulation
and the list registers, which represent the guest's view of IRQs.
This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
which gets called on guest entry and exit.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h     |   4 +
 virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h    |   4 +
 4 files changed, 373 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index f32b284..986f23f 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
 
+bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
+
 /**
  * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
  *
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 0bf6f27..1cec423 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -14,11 +14,172 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/irqchip/arm-gic.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 
 #include "vgic.h"
 
+/*
+ * Call this function to convert a u64 value to an unsigned long * bitmask
+ * in a way that works on both 32-bit and 64-bit LE and BE platforms.
+ *
+ * Warning: Calling this function may modify *val.
+ */
+static unsigned long *u64_to_bitmask(u64 *val)
+{
+#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
+	*val = (*val >> 32) | (*val << 32);
+#endif
+	return (unsigned long *)val;
+}
+
+void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+
+	if (cpuif->vgic_misr & GICH_MISR_EOI) {
+		u64 eisr = cpuif->vgic_eisr;
+		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
+		int lr;
+
+		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
+			struct vgic_irq *irq;
+			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
+
+			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
+			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
+
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
+			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
+			cpuif->vgic_elrsr |= 1ULL << lr;
+		}
+	}
+
+	/* check and disable underflow maintenance IRQ */
+	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
+
+	/*
+	 * In the next iterations of the vcpu loop, if we sync the
+	 * vgic state after flushing it, but before entering the guest
+	 * (this happens for pending signals and vmid rollovers), then
+	 * make sure we don't pick up any old maintenance interrupts
+	 * here.
+	 */
+	cpuif->vgic_eisr = 0;
+}
+
+void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+
+	cpuif->vgic_hcr |= GICH_HCR_UIE;
+}
+
+/*
+ * transfer the content of the LRs back into the corresponding ap_list:
+ * - active bit is transferred as is
+ * - pending bit is
+ *   - transferred as is in case of edge sensitive IRQs
+ *   - set to the line-level (resample time) for level sensitive IRQs
+ */
+void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+	int lr;
+
+	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
+		u32 val = cpuif->vgic_lr[lr];
+		u32 intid = val & GICH_LR_VIRTUALID;
+		struct vgic_irq *irq;
+
+		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+
+		/* Always preserve the active bit */
+		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
+
+		/* Edge is the only case where we preserve the pending bit */
+		if (irq->config == VGIC_CONFIG_EDGE &&
+		    (val & GICH_LR_PENDING_BIT)) {
+			irq->pending = true;
+
+			if (intid < VGIC_NR_SGIS) {
+				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
+
+				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
+				irq->source |= (1 << cpuid);
+			}
+		}
+
+		/* Clear soft pending state when level IRQs have been acked */
+		if (irq->config == VGIC_CONFIG_LEVEL &&
+		    !(val & GICH_LR_PENDING_BIT)) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		}
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+/*
+ * Populates the particular LR with the state of a given IRQ:
+ * - for an edge sensitive IRQ the pending state is reset in the struct
+ * - for a level sensitive IRQ the pending state value is unchanged;
+ *   it will be resampled on deactivation
+ *
+ * If irq is not NULL, the irq_lock must be hold already by the caller.
+ * If irq is NULL, the respective LR gets cleared.
+ */
+void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
+{
+	u32 val;
+
+	if (!irq) {
+		val = 0;
+		goto out;
+	}
+
+	val = irq->intid;
+
+	if (irq->pending) {
+		val |= GICH_LR_PENDING_BIT;
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			irq->pending = false;
+
+		if (irq->intid < VGIC_NR_SGIS) {
+			u32 src = ffs(irq->source);
+
+			BUG_ON(!src);
+			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
+			irq->source &= ~(1 << (src - 1));
+			if (irq->source)
+				irq->pending = true;
+		}
+	}
+
+	if (irq->active)
+		val |= GICH_LR_ACTIVE_BIT;
+
+	if (irq->hw) {
+		val |= GICH_LR_HW;
+		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
+	} else {
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			val |= GICH_LR_EOI;
+	}
+
+out:
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
+}
+
 void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 29c753e..90a85bf 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 	vgic_update_irq_pending(kvm, vcpu, intid, level);
 	return 0;
 }
+
+/**
+ * vgic_prune_ap_list - Remove non-relevant interrupts from the list
+ *
+ * @vcpu: The VCPU pointer
+ *
+ * Go over the list of "interesting" interrupts, and prune those that we
+ * won't have to consider in the near future.
+ */
+static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq, *tmp;
+
+retry:
+	spin_lock(&vgic_cpu->ap_list_lock);
+
+	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
+		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
+
+		spin_lock(&irq->irq_lock);
+
+		BUG_ON(vcpu != irq->vcpu);
+
+		target_vcpu = vgic_target_oracle(irq);
+
+		if (!target_vcpu) {
+			/*
+			 * We don't need to process this interrupt any
+			 * further, move it off the list.
+			 */
+			list_del_init(&irq->ap_list);
+			irq->vcpu = NULL;
+			spin_unlock(&irq->irq_lock);
+			continue;
+		}
+
+		if (target_vcpu == vcpu) {
+			/* We're on the right CPU */
+			spin_unlock(&irq->irq_lock);
+			continue;
+		}
+
+		/* This interrupt looks like it has to be migrated. */
+
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vgic_cpu->ap_list_lock);
+
+		/*
+		 * Ensure locking order by always locking the smallest
+		 * ID first.
+		 */
+		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
+			vcpuA = vcpu;
+			vcpuB = target_vcpu;
+		} else {
+			vcpuA = target_vcpu;
+			vcpuB = vcpu;
+		}
+
+		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
+		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
+		spin_lock(&irq->irq_lock);
+
+		/*
+		 * If the affinity has been preserved, move the
+		 * interrupt around. Otherwise, it means things have
+		 * changed while the interrupt was unlocked, and we
+		 * need to replay this.
+		 *
+		 * In all cases, we cannot trust the list not to have
+		 * changed, so we restart from the beginning.
+		 */
+		if (target_vcpu == vgic_target_oracle(irq)) {
+			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
+
+			list_del_init(&irq->ap_list);
+			irq->vcpu = target_vcpu;
+			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
+		}
+
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
+		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
+		goto retry;
+	}
+
+	spin_unlock(&vgic_cpu->ap_list_lock);
+}
+
+static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_process_maintenance(vcpu);
+	else
+		WARN(1, "GICv3 Not Implemented\n");
+}
+
+static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_fold_lr_state(vcpu);
+	else
+		WARN(1, "GICv3 Not Implemented\n");
+}
+
+/*
+ * Requires the ap_lock to be held.
+ * If irq is not NULL, requires the IRQ lock to be held as well.
+ * If irq is NULL, the list register gets cleared.
+ */
+static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
+				    struct vgic_irq *irq, int lr)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_populate_lr(vcpu, irq, lr);
+	else
+		WARN(1, "GICv3 Not Implemented\n");
+}
+
+static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_set_underflow(vcpu);
+	else
+		WARN(1, "GICv3 Not Implemented\n");
+}
+
+static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq;
+	int count = 0;
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+		/* GICv2 SGIs can count for more than one... */
+		if (irq->intid < VGIC_NR_SGIS && irq->source)
+			count += hweight8(irq->source);
+		else
+			count++;
+		spin_unlock(&irq->irq_lock);
+	}
+	return count;
+}
+
+/* requires the vcpu ap_lock to be held */
+static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	struct vgic_irq *irq;
+	int count = 0;
+
+	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
+		vgic_set_underflow(vcpu);
+		vgic_sort_ap_list(vcpu);
+	}
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+
+		if (unlikely(vgic_target_oracle(irq) != vcpu))
+			goto next;
+
+		/*
+		 * If we get an SGI with multiple sources, try to get
+		 * them in all at once.
+		 */
+		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
+		    irq->intid < VGIC_NR_SGIS) {
+			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
+				vgic_populate_lr(vcpu, irq, count++);
+		} else {
+			vgic_populate_lr(vcpu, irq, count++);
+		}
+
+next:
+		spin_unlock(&irq->irq_lock);
+
+		if (count == vcpu->arch.vgic_cpu.nr_lr)
+			break;
+	}
+
+	vcpu->arch.vgic_cpu.used_lrs = count;
+
+	/* Nuke remaining LRs */
+	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
+		vgic_populate_lr(vcpu, NULL, count);
+}
+
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
+{
+	vgic_process_maintenance_interrupt(vcpu);
+	vgic_fold_lr_state(vcpu);
+	vgic_prune_ap_list(vcpu);
+}
+
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+	vgic_populate_lrs(vcpu);
+	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index b2faf00..95ef3cf 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -21,5 +21,9 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
 
 void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
+void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
+void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
+void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 
 #endif
-- 
2.7.3

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

* [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marc Zyngier <marc.zyngier@arm.com>

Implement the functionality for syncing IRQs between our emulation
and the list registers, which represent the guest's view of IRQs.
This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
which gets called on guest entry and exit.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h     |   4 +
 virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h    |   4 +
 4 files changed, 373 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index f32b284..986f23f 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
 
+bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
+
 /**
  * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
  *
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 0bf6f27..1cec423 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -14,11 +14,172 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/irqchip/arm-gic.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 
 #include "vgic.h"
 
+/*
+ * Call this function to convert a u64 value to an unsigned long * bitmask
+ * in a way that works on both 32-bit and 64-bit LE and BE platforms.
+ *
+ * Warning: Calling this function may modify *val.
+ */
+static unsigned long *u64_to_bitmask(u64 *val)
+{
+#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
+	*val = (*val >> 32) | (*val << 32);
+#endif
+	return (unsigned long *)val;
+}
+
+void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+
+	if (cpuif->vgic_misr & GICH_MISR_EOI) {
+		u64 eisr = cpuif->vgic_eisr;
+		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
+		int lr;
+
+		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
+			struct vgic_irq *irq;
+			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
+
+			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
+			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
+
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
+			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
+			cpuif->vgic_elrsr |= 1ULL << lr;
+		}
+	}
+
+	/* check and disable underflow maintenance IRQ */
+	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
+
+	/*
+	 * In the next iterations of the vcpu loop, if we sync the
+	 * vgic state after flushing it, but before entering the guest
+	 * (this happens for pending signals and vmid rollovers), then
+	 * make sure we don't pick up any old maintenance interrupts
+	 * here.
+	 */
+	cpuif->vgic_eisr = 0;
+}
+
+void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+
+	cpuif->vgic_hcr |= GICH_HCR_UIE;
+}
+
+/*
+ * transfer the content of the LRs back into the corresponding ap_list:
+ * - active bit is transferred as is
+ * - pending bit is
+ *   - transferred as is in case of edge sensitive IRQs
+ *   - set to the line-level (resample time) for level sensitive IRQs
+ */
+void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+	int lr;
+
+	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
+		u32 val = cpuif->vgic_lr[lr];
+		u32 intid = val & GICH_LR_VIRTUALID;
+		struct vgic_irq *irq;
+
+		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+
+		/* Always preserve the active bit */
+		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
+
+		/* Edge is the only case where we preserve the pending bit */
+		if (irq->config == VGIC_CONFIG_EDGE &&
+		    (val & GICH_LR_PENDING_BIT)) {
+			irq->pending = true;
+
+			if (intid < VGIC_NR_SGIS) {
+				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
+
+				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
+				irq->source |= (1 << cpuid);
+			}
+		}
+
+		/* Clear soft pending state when level IRQs have been acked */
+		if (irq->config == VGIC_CONFIG_LEVEL &&
+		    !(val & GICH_LR_PENDING_BIT)) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		}
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+/*
+ * Populates the particular LR with the state of a given IRQ:
+ * - for an edge sensitive IRQ the pending state is reset in the struct
+ * - for a level sensitive IRQ the pending state value is unchanged;
+ *   it will be resampled on deactivation
+ *
+ * If irq is not NULL, the irq_lock must be hold already by the caller.
+ * If irq is NULL, the respective LR gets cleared.
+ */
+void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
+{
+	u32 val;
+
+	if (!irq) {
+		val = 0;
+		goto out;
+	}
+
+	val = irq->intid;
+
+	if (irq->pending) {
+		val |= GICH_LR_PENDING_BIT;
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			irq->pending = false;
+
+		if (irq->intid < VGIC_NR_SGIS) {
+			u32 src = ffs(irq->source);
+
+			BUG_ON(!src);
+			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
+			irq->source &= ~(1 << (src - 1));
+			if (irq->source)
+				irq->pending = true;
+		}
+	}
+
+	if (irq->active)
+		val |= GICH_LR_ACTIVE_BIT;
+
+	if (irq->hw) {
+		val |= GICH_LR_HW;
+		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
+	} else {
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			val |= GICH_LR_EOI;
+	}
+
+out:
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
+}
+
 void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 29c753e..90a85bf 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 	vgic_update_irq_pending(kvm, vcpu, intid, level);
 	return 0;
 }
+
+/**
+ * vgic_prune_ap_list - Remove non-relevant interrupts from the list
+ *
+ * @vcpu: The VCPU pointer
+ *
+ * Go over the list of "interesting" interrupts, and prune those that we
+ * won't have to consider in the near future.
+ */
+static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq, *tmp;
+
+retry:
+	spin_lock(&vgic_cpu->ap_list_lock);
+
+	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
+		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
+
+		spin_lock(&irq->irq_lock);
+
+		BUG_ON(vcpu != irq->vcpu);
+
+		target_vcpu = vgic_target_oracle(irq);
+
+		if (!target_vcpu) {
+			/*
+			 * We don't need to process this interrupt any
+			 * further, move it off the list.
+			 */
+			list_del_init(&irq->ap_list);
+			irq->vcpu = NULL;
+			spin_unlock(&irq->irq_lock);
+			continue;
+		}
+
+		if (target_vcpu == vcpu) {
+			/* We're on the right CPU */
+			spin_unlock(&irq->irq_lock);
+			continue;
+		}
+
+		/* This interrupt looks like it has to be migrated. */
+
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vgic_cpu->ap_list_lock);
+
+		/*
+		 * Ensure locking order by always locking the smallest
+		 * ID first.
+		 */
+		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
+			vcpuA = vcpu;
+			vcpuB = target_vcpu;
+		} else {
+			vcpuA = target_vcpu;
+			vcpuB = vcpu;
+		}
+
+		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
+		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
+		spin_lock(&irq->irq_lock);
+
+		/*
+		 * If the affinity has been preserved, move the
+		 * interrupt around. Otherwise, it means things have
+		 * changed while the interrupt was unlocked, and we
+		 * need to replay this.
+		 *
+		 * In all cases, we cannot trust the list not to have
+		 * changed, so we restart from the beginning.
+		 */
+		if (target_vcpu == vgic_target_oracle(irq)) {
+			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
+
+			list_del_init(&irq->ap_list);
+			irq->vcpu = target_vcpu;
+			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
+		}
+
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
+		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
+		goto retry;
+	}
+
+	spin_unlock(&vgic_cpu->ap_list_lock);
+}
+
+static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_process_maintenance(vcpu);
+	else
+		WARN(1, "GICv3 Not Implemented\n");
+}
+
+static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_fold_lr_state(vcpu);
+	else
+		WARN(1, "GICv3 Not Implemented\n");
+}
+
+/*
+ * Requires the ap_lock to be held.
+ * If irq is not NULL, requires the IRQ lock to be held as well.
+ * If irq is NULL, the list register gets cleared.
+ */
+static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
+				    struct vgic_irq *irq, int lr)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_populate_lr(vcpu, irq, lr);
+	else
+		WARN(1, "GICv3 Not Implemented\n");
+}
+
+static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_set_underflow(vcpu);
+	else
+		WARN(1, "GICv3 Not Implemented\n");
+}
+
+static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq;
+	int count = 0;
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+		/* GICv2 SGIs can count for more than one... */
+		if (irq->intid < VGIC_NR_SGIS && irq->source)
+			count += hweight8(irq->source);
+		else
+			count++;
+		spin_unlock(&irq->irq_lock);
+	}
+	return count;
+}
+
+/* requires the vcpu ap_lock to be held */
+static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	struct vgic_irq *irq;
+	int count = 0;
+
+	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
+		vgic_set_underflow(vcpu);
+		vgic_sort_ap_list(vcpu);
+	}
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+
+		if (unlikely(vgic_target_oracle(irq) != vcpu))
+			goto next;
+
+		/*
+		 * If we get an SGI with multiple sources, try to get
+		 * them in all at once.
+		 */
+		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
+		    irq->intid < VGIC_NR_SGIS) {
+			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
+				vgic_populate_lr(vcpu, irq, count++);
+		} else {
+			vgic_populate_lr(vcpu, irq, count++);
+		}
+
+next:
+		spin_unlock(&irq->irq_lock);
+
+		if (count == vcpu->arch.vgic_cpu.nr_lr)
+			break;
+	}
+
+	vcpu->arch.vgic_cpu.used_lrs = count;
+
+	/* Nuke remaining LRs */
+	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
+		vgic_populate_lr(vcpu, NULL, count);
+}
+
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
+{
+	vgic_process_maintenance_interrupt(vcpu);
+	vgic_fold_lr_state(vcpu);
+	vgic_prune_ap_list(vcpu);
+}
+
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+	vgic_populate_lrs(vcpu);
+	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index b2faf00..95ef3cf 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -21,5 +21,9 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
 
 void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
+void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
+void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
+void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 
 #endif
-- 
2.7.3

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

* [RFC PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

As the GICv3 virtual interface registers differ from their GICv2
siblings, we need different handlers for processing maintenance
interrupts and reading/writing to the LRs.
Also as we store an IRQ's affinity directly as a MPIDR, we need a
separate change_affinity() implementation too.
Implement the respective handler functions and connect them to
existing code to be called if the host is using a GICv3.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-v3.c | 191 ++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c    |   8 +-
 virt/kvm/arm/vgic/vgic.h    |  30 +++++++
 3 files changed, 225 insertions(+), 4 deletions(-)
 create mode 100644 virt/kvm/arm/vgic/vgic-v3.c

diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
new file mode 100644
index 0000000..71b4bad
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -0,0 +1,191 @@
+/*
+ * 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/irqchip/arm-gic-v3.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/irqchip/arm-gic.h>
+
+#include "vgic.h"
+
+void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+
+	if (cpuif->vgic_misr & ICH_MISR_EOI) {
+		unsigned long eisr_bmap = cpuif->vgic_eisr;
+		int lr;
+
+		for_each_set_bit(lr, &eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
+			u32 intid;
+			u64 val = cpuif->vgic_lr[lr];
+
+			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+				intid = val & ICH_LR_VIRTUAL_ID_MASK;
+			else
+				intid = val & GICH_LR_VIRTUALID;
+
+			/*
+			 * kvm_notify_acked_irq calls kvm_set_irq()
+			 * to reset the IRQ level, which grabs the dist->lock
+			 * so we call this before taking the dist->lock.
+			 */
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
+			cpuif->vgic_lr[lr] &= ~ICH_LR_STATE; /* Useful?? */
+			cpuif->vgic_elrsr |= 1ULL << lr;
+		}
+
+		/*
+		 * In the next iterations of the vcpu loop, if we sync
+		 * the vgic state after flushing it, but before
+		 * entering the guest (this happens for pending
+		 * signals and vmid rollovers), then make sure we
+		 * don't pick up any old maintenance interrupts here.
+		 */
+		cpuif->vgic_eisr = 0;
+	}
+
+	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
+}
+
+void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	cpuif->vgic_hcr |= ICH_HCR_UIE;
+}
+
+void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	int lr;
+
+	/* Assumes ap_list_lock held */
+
+	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
+		u64 val = cpuif->vgic_lr[lr];
+		u32 intid;
+		struct vgic_irq *irq;
+
+		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+			intid = val & ICH_LR_VIRTUAL_ID_MASK;
+		else
+			intid = val & GICH_LR_VIRTUALID;
+		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+
+		/* Always preserve the active bit */
+		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
+
+		/* Edge is the only case where we preserve the pending bit */
+		if (irq->config == VGIC_CONFIG_EDGE &&
+		    (val & ICH_LR_PENDING_BIT)) {
+			irq->pending = true;
+
+			if (intid < VGIC_NR_SGIS &&
+			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
+
+				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
+				irq->source |= (1 << cpuid);
+			}
+		}
+
+		/* Clear soft pending state when level irqs have been acked */
+		if (irq->config == VGIC_CONFIG_LEVEL &&
+		    !(val & ICH_LR_PENDING_BIT)) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		}
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+/* Requires the irq to be locked already */
+void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
+{
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	u64 val;
+
+	if (!irq) {
+		val = 0;
+		goto out;
+	}
+
+	val = irq->intid;
+
+	if (irq->pending) {
+		val |= ICH_LR_PENDING_BIT;
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			irq->pending = false;
+
+		if (irq->intid < VGIC_NR_SGIS &&
+		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+			u32 src = ffs(irq->source);
+
+			BUG_ON(!src);
+			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
+			irq->source &= ~(1 << (src - 1));
+			if (irq->source)
+				irq->pending = true;
+		}
+	}
+
+	if (irq->active)
+		val |= ICH_LR_ACTIVE_BIT;
+
+	if (irq->hw) {
+		val |= ICH_LR_HW;
+		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
+	} else {
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			val |= ICH_LR_EOI;
+	}
+
+	/*
+	 * Currently all guest IRQs are Group1, as Group0 would result
+	 * in a FIQ in the guest, which it wouldn't expect.
+	 * Eventually we want to make this configurable, so we may
+	 * revisit this in the future.
+	 */
+	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+		val |= ICH_LR_GROUP;
+
+out:
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
+}
+
+void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct vgic_irq *irq;
+	struct kvm_vcpu *vcpu;
+
+	BUG_ON(intid <= VGIC_MAX_PRIVATE || intid > 1019);
+	BUG_ON(dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3);
+
+	irq = vgic_get_irq(kvm, NULL, intid);
+	vcpu = kvm_mpidr_to_vcpu(kvm, mpidr);
+
+	spin_lock(&irq->irq_lock);
+	irq->target_vcpu = vcpu;
+	spin_unlock(&irq->irq_lock);
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 90a85bf..9eb031e8 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -368,7 +368,7 @@ static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
 	if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_process_maintenance(vcpu);
 	else
-		WARN(1, "GICv3 Not Implemented\n");
+		vgic_v3_process_maintenance(vcpu);
 }
 
 static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
@@ -376,7 +376,7 @@ static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
 	if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_fold_lr_state(vcpu);
 	else
-		WARN(1, "GICv3 Not Implemented\n");
+		vgic_v3_fold_lr_state(vcpu);
 }
 
 /*
@@ -390,7 +390,7 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
 	if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_populate_lr(vcpu, irq, lr);
 	else
-		WARN(1, "GICv3 Not Implemented\n");
+		vgic_v3_populate_lr(vcpu, irq, lr);
 }
 
 static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
@@ -398,7 +398,7 @@ static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
 	if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_set_underflow(vcpu);
 	else
-		WARN(1, "GICv3 Not Implemented\n");
+		vgic_v3_set_underflow(vcpu);
 }
 
 static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 95ef3cf..53730ba 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -26,4 +26,34 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
+void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
+void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
+void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+#else
+static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
+					       u64 mpidr)
+{
+}
+
+static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
+{
+}
+
+static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+}
+
+static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
+				       struct vgic_irq *irq, int lr)
+{
+}
+
+static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
+{
+}
+#endif
+
 #endif
-- 
2.7.3

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

* [RFC PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marc Zyngier <marc.zyngier@arm.com>

As the GICv3 virtual interface registers differ from their GICv2
siblings, we need different handlers for processing maintenance
interrupts and reading/writing to the LRs.
Also as we store an IRQ's affinity directly as a MPIDR, we need a
separate change_affinity() implementation too.
Implement the respective handler functions and connect them to
existing code to be called if the host is using a GICv3.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-v3.c | 191 ++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c    |   8 +-
 virt/kvm/arm/vgic/vgic.h    |  30 +++++++
 3 files changed, 225 insertions(+), 4 deletions(-)
 create mode 100644 virt/kvm/arm/vgic/vgic-v3.c

diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
new file mode 100644
index 0000000..71b4bad
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -0,0 +1,191 @@
+/*
+ * 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/irqchip/arm-gic-v3.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/irqchip/arm-gic.h>
+
+#include "vgic.h"
+
+void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+
+	if (cpuif->vgic_misr & ICH_MISR_EOI) {
+		unsigned long eisr_bmap = cpuif->vgic_eisr;
+		int lr;
+
+		for_each_set_bit(lr, &eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
+			u32 intid;
+			u64 val = cpuif->vgic_lr[lr];
+
+			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+				intid = val & ICH_LR_VIRTUAL_ID_MASK;
+			else
+				intid = val & GICH_LR_VIRTUALID;
+
+			/*
+			 * kvm_notify_acked_irq calls kvm_set_irq()
+			 * to reset the IRQ level, which grabs the dist->lock
+			 * so we call this before taking the dist->lock.
+			 */
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
+			cpuif->vgic_lr[lr] &= ~ICH_LR_STATE; /* Useful?? */
+			cpuif->vgic_elrsr |= 1ULL << lr;
+		}
+
+		/*
+		 * In the next iterations of the vcpu loop, if we sync
+		 * the vgic state after flushing it, but before
+		 * entering the guest (this happens for pending
+		 * signals and vmid rollovers), then make sure we
+		 * don't pick up any old maintenance interrupts here.
+		 */
+		cpuif->vgic_eisr = 0;
+	}
+
+	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
+}
+
+void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	cpuif->vgic_hcr |= ICH_HCR_UIE;
+}
+
+void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	int lr;
+
+	/* Assumes ap_list_lock held */
+
+	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
+		u64 val = cpuif->vgic_lr[lr];
+		u32 intid;
+		struct vgic_irq *irq;
+
+		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+			intid = val & ICH_LR_VIRTUAL_ID_MASK;
+		else
+			intid = val & GICH_LR_VIRTUALID;
+		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+
+		/* Always preserve the active bit */
+		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
+
+		/* Edge is the only case where we preserve the pending bit */
+		if (irq->config == VGIC_CONFIG_EDGE &&
+		    (val & ICH_LR_PENDING_BIT)) {
+			irq->pending = true;
+
+			if (intid < VGIC_NR_SGIS &&
+			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
+
+				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
+				irq->source |= (1 << cpuid);
+			}
+		}
+
+		/* Clear soft pending state when level irqs have been acked */
+		if (irq->config == VGIC_CONFIG_LEVEL &&
+		    !(val & ICH_LR_PENDING_BIT)) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		}
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+/* Requires the irq to be locked already */
+void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
+{
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	u64 val;
+
+	if (!irq) {
+		val = 0;
+		goto out;
+	}
+
+	val = irq->intid;
+
+	if (irq->pending) {
+		val |= ICH_LR_PENDING_BIT;
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			irq->pending = false;
+
+		if (irq->intid < VGIC_NR_SGIS &&
+		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+			u32 src = ffs(irq->source);
+
+			BUG_ON(!src);
+			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
+			irq->source &= ~(1 << (src - 1));
+			if (irq->source)
+				irq->pending = true;
+		}
+	}
+
+	if (irq->active)
+		val |= ICH_LR_ACTIVE_BIT;
+
+	if (irq->hw) {
+		val |= ICH_LR_HW;
+		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
+	} else {
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			val |= ICH_LR_EOI;
+	}
+
+	/*
+	 * Currently all guest IRQs are Group1, as Group0 would result
+	 * in a FIQ in the guest, which it wouldn't expect.
+	 * Eventually we want to make this configurable, so we may
+	 * revisit this in the future.
+	 */
+	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+		val |= ICH_LR_GROUP;
+
+out:
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
+}
+
+void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct vgic_irq *irq;
+	struct kvm_vcpu *vcpu;
+
+	BUG_ON(intid <= VGIC_MAX_PRIVATE || intid > 1019);
+	BUG_ON(dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3);
+
+	irq = vgic_get_irq(kvm, NULL, intid);
+	vcpu = kvm_mpidr_to_vcpu(kvm, mpidr);
+
+	spin_lock(&irq->irq_lock);
+	irq->target_vcpu = vcpu;
+	spin_unlock(&irq->irq_lock);
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 90a85bf..9eb031e8 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -368,7 +368,7 @@ static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
 	if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_process_maintenance(vcpu);
 	else
-		WARN(1, "GICv3 Not Implemented\n");
+		vgic_v3_process_maintenance(vcpu);
 }
 
 static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
@@ -376,7 +376,7 @@ static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
 	if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_fold_lr_state(vcpu);
 	else
-		WARN(1, "GICv3 Not Implemented\n");
+		vgic_v3_fold_lr_state(vcpu);
 }
 
 /*
@@ -390,7 +390,7 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
 	if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_populate_lr(vcpu, irq, lr);
 	else
-		WARN(1, "GICv3 Not Implemented\n");
+		vgic_v3_populate_lr(vcpu, irq, lr);
 }
 
 static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
@@ -398,7 +398,7 @@ static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
 	if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_set_underflow(vcpu);
 	else
-		WARN(1, "GICv3 Not Implemented\n");
+		vgic_v3_set_underflow(vcpu);
 }
 
 static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 95ef3cf..53730ba 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -26,4 +26,34 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
+void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
+void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
+void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+#else
+static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
+					       u64 mpidr)
+{
+}
+
+static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
+{
+}
+
+static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+}
+
+static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
+				       struct vgic_irq *irq, int lr)
+{
+}
+
+static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
+{
+}
+#endif
+
 #endif
-- 
2.7.3

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

* [RFC PATCH 11/45] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: kvmarm, kvm, linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

Tell KVM whether a particular VCPU has an IRQ that needs handling
in the guest. This is used to decide whether a VCPU is runnable.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h  |  2 ++
 virt/kvm/arm/vgic/vgic.c | 22 ++++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 986f23f..2ce9b4a 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -181,6 +181,8 @@ struct vgic_cpu {
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
 
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
+
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(false)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 9eb031e8..d6c8c92 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -477,3 +477,25 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	vgic_populate_lrs(vcpu);
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
 }
+
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq;
+	bool pending = false;
+
+	spin_lock(&vgic_cpu->ap_list_lock);
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+		pending = irq->pending && irq->enabled;
+		spin_unlock(&irq->irq_lock);
+
+		if (pending)
+			break;
+	}
+
+	spin_unlock(&vgic_cpu->ap_list_lock);
+
+	return pending;
+}
-- 
2.7.3


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

* [RFC PATCH 11/45] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

Tell KVM whether a particular VCPU has an IRQ that needs handling
in the guest. This is used to decide whether a VCPU is runnable.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h  |  2 ++
 virt/kvm/arm/vgic/vgic.c | 22 ++++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 986f23f..2ce9b4a 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -181,6 +181,8 @@ struct vgic_cpu {
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
 
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
+
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(false)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 9eb031e8..d6c8c92 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -477,3 +477,25 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	vgic_populate_lrs(vcpu);
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
 }
+
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq;
+	bool pending = false;
+
+	spin_lock(&vgic_cpu->ap_list_lock);
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+		pending = irq->pending && irq->enabled;
+		spin_unlock(&irq->irq_lock);
+
+		if (pending)
+			break;
+	}
+
+	spin_unlock(&vgic_cpu->ap_list_lock);
+
+	return pending;
+}
-- 
2.7.3

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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: kvmarm, kvm, linux-arm-kernel

We register each register group of the distributor and redistributors
as separate regions of the kvm-io-bus framework. This way calls get
directly handed over to the actual handler.
This puts a lot more regions into kvm-io-bus than what we use at the
moment on other architectures, so we will probably need to revisit the
implementation of the framework later to be more efficient.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
---
 include/kvm/vgic/vgic.h       |   9 ++
 virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
 3 files changed, 250 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
 create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2ce9b4a..a8262c7 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -106,6 +106,12 @@ struct vgic_irq {
 	enum vgic_irq_config config;	/* Level or edge */
 };
 
+struct vgic_io_device {
+	gpa_t base_addr;
+	struct kvm_vcpu *redist_vcpu;
+	struct kvm_io_device dev;
+};
+
 struct vgic_dist {
 	bool			in_kernel;
 	bool			ready;
@@ -132,6 +138,9 @@ struct vgic_dist {
 	u32			enabled;
 
 	struct vgic_irq		*spis;
+
+	struct vgic_io_device	*dist_iodevs;
+	struct vgic_io_device	*redist_iodevs;
 };
 
 struct vgic_v2_cpu_if {
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
new file mode 100644
index 0000000..26c46e7
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -0,0 +1,194 @@
+/*
+ * VGIC MMIO handling functions
+ *
+ * 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.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/iodev.h>
+#include <kvm/vgic/vgic.h>
+#include <linux/bitops.h>
+#include <linux/irqchip/arm-gic.h>
+
+#include "vgic.h"
+#include "vgic_mmio.h"
+
+void write_mask32(u32 value, int offset, int len, void *val)
+{
+	value = cpu_to_le32(value) >> (offset * 8);
+	memcpy(val, &value, len);
+}
+
+u32 mask32(u32 origvalue, int offset, int len, const void *val)
+{
+	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
+	memcpy((char *)&origvalue + (offset * 8), val, len);
+	return origvalue;
+}
+
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void write_mask64(u64 value, int offset, int len, void *val)
+{
+	value = cpu_to_le64(value) >> (offset * 8);
+	memcpy(val, &value, len);
+}
+
+/* FIXME: I am clearly misguided here, there must be some saner way ... */
+u64 mask64(u64 origvalue, int offset, int len, const void *val)
+{
+	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
+	memcpy((char *)&origvalue + (offset * 8), val, len);
+	return origvalue;
+}
+#endif
+
+int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+		       gpa_t addr, int len, void *val)
+{
+	memset(val, 0, len);
+
+	return 0;
+}
+
+int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+		       gpa_t addr, int len, const void *val)
+{
+	return 0;
+}
+
+static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
+			      struct kvm_io_device *this,
+			      gpa_t addr, int len, void *val)
+{
+	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
+		vcpu->vcpu_id, (unsigned long long)addr);
+	return 0;
+}
+
+static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
+			       struct kvm_io_device *this,
+			       gpa_t addr, int len, const void *val)
+{
+	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
+		vcpu->vcpu_id, (unsigned long long)addr);
+	return 0;
+}
+
+struct vgic_register_region vgic_v2_dist_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+};
+
+int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
+				  struct vgic_register_region *reg_desc,
+				  struct vgic_io_device *region,
+				  int nr_irqs, bool offset_private)
+{
+	int bpi = reg_desc->bits_per_irq;
+	int offset = 0;
+	int len, ret;
+
+	region->base_addr	+= reg_desc->reg_offset;
+	region->redist_vcpu	= vcpu;
+
+	kvm_iodevice_init(&region->dev, &reg_desc->ops);
+
+	if (bpi) {
+		len = (bpi * nr_irqs) / 8;
+		if (offset_private)
+			offset = (bpi * VGIC_NR_PRIVATE_IRQS) / 8;
+	} else {
+		len = reg_desc->len;
+	}
+
+	mutex_lock(&kvm->slots_lock);
+	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+				      region->base_addr + offset,
+				      len - offset, &region->dev);
+	mutex_unlock(&kvm->slots_lock);
+
+	return ret;
+}
+
+int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
+			       enum vgic_type type)
+{
+	struct vgic_io_device *regions;
+	struct vgic_register_region *reg_desc;
+	int nr_regions;
+	int nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+	int i;
+	int ret = 0;
+
+	switch (type) {
+	case VGIC_V2:
+		reg_desc = vgic_v2_dist_registers;
+		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+		break;
+	default:
+		BUG_ON(1);
+	}
+
+	regions = kmalloc_array(nr_regions, sizeof(struct vgic_io_device),
+				GFP_KERNEL);
+	if (!regions)
+		return -ENOMEM;
+
+	for (i = 0; i < nr_regions; i++) {
+		regions[i].base_addr	= dist_base_address;
+
+		ret = kvm_vgic_register_mmio_region(kvm, NULL, reg_desc,
+						    regions + i, nr_irqs,
+						    type == VGIC_V3);
+		if (ret)
+			break;
+
+		reg_desc++;
+	}
+
+	if (ret) {
+		mutex_lock(&kvm->slots_lock);
+		for (i--; i >= 0; i--)
+			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+						  &regions[i].dev);
+		mutex_unlock(&kvm->slots_lock);
+	} else {
+		kvm->arch.vgic.dist_iodevs = regions;
+	}
+
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic_mmio.h b/virt/kvm/arm/vgic/vgic_mmio.h
new file mode 100644
index 0000000..cf2314c
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_mmio.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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_ARM_VGIC_MMIO_H__
+#define __KVM_ARM_VGIC_MMIO_H__
+
+struct vgic_register_region {
+	int reg_offset;
+	int len;
+	int bits_per_irq;
+	struct kvm_io_device_ops ops;
+};
+
+#define REGISTER_DESC_WITH_BITS_PER_IRQ(name, read_ops, write_ops, bpi) \
+	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
+	 .ops.read = read_ops, .ops.write = write_ops}
+#define REGISTER_DESC_WITH_LENGTH(name, read_ops, write_ops, length) \
+	{.reg_offset = name, .bits_per_irq = 0, .len = length, \
+	 .ops.read = read_ops, .ops.write = write_ops}
+
+int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+		       gpa_t addr, int len, void *val);
+int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+		       gpa_t addr, int len, const void *val);
+int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
+				  struct vgic_register_region *reg_desc,
+				  struct vgic_io_device *region,
+				  int nr_irqs, bool offset_private);
+
+void write_mask32(u32 value, int offset, int len, void *val);
+void write_mask64(u64 value, int offset, int len, void *val);
+u32 mask32(u32 origvalue, int offset, int len, const void *val);
+u64 mask64(u64 origvalue, int offset, int len, const void *val);
+
+#endif
-- 
2.7.3


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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

We register each register group of the distributor and redistributors
as separate regions of the kvm-io-bus framework. This way calls get
directly handed over to the actual handler.
This puts a lot more regions into kvm-io-bus than what we use at the
moment on other architectures, so we will probably need to revisit the
implementation of the framework later to be more efficient.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
---
 include/kvm/vgic/vgic.h       |   9 ++
 virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
 3 files changed, 250 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
 create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2ce9b4a..a8262c7 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -106,6 +106,12 @@ struct vgic_irq {
 	enum vgic_irq_config config;	/* Level or edge */
 };
 
+struct vgic_io_device {
+	gpa_t base_addr;
+	struct kvm_vcpu *redist_vcpu;
+	struct kvm_io_device dev;
+};
+
 struct vgic_dist {
 	bool			in_kernel;
 	bool			ready;
@@ -132,6 +138,9 @@ struct vgic_dist {
 	u32			enabled;
 
 	struct vgic_irq		*spis;
+
+	struct vgic_io_device	*dist_iodevs;
+	struct vgic_io_device	*redist_iodevs;
 };
 
 struct vgic_v2_cpu_if {
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
new file mode 100644
index 0000000..26c46e7
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -0,0 +1,194 @@
+/*
+ * VGIC MMIO handling functions
+ *
+ * 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.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/iodev.h>
+#include <kvm/vgic/vgic.h>
+#include <linux/bitops.h>
+#include <linux/irqchip/arm-gic.h>
+
+#include "vgic.h"
+#include "vgic_mmio.h"
+
+void write_mask32(u32 value, int offset, int len, void *val)
+{
+	value = cpu_to_le32(value) >> (offset * 8);
+	memcpy(val, &value, len);
+}
+
+u32 mask32(u32 origvalue, int offset, int len, const void *val)
+{
+	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
+	memcpy((char *)&origvalue + (offset * 8), val, len);
+	return origvalue;
+}
+
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void write_mask64(u64 value, int offset, int len, void *val)
+{
+	value = cpu_to_le64(value) >> (offset * 8);
+	memcpy(val, &value, len);
+}
+
+/* FIXME: I am clearly misguided here, there must be some saner way ... */
+u64 mask64(u64 origvalue, int offset, int len, const void *val)
+{
+	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
+	memcpy((char *)&origvalue + (offset * 8), val, len);
+	return origvalue;
+}
+#endif
+
+int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+		       gpa_t addr, int len, void *val)
+{
+	memset(val, 0, len);
+
+	return 0;
+}
+
+int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+		       gpa_t addr, int len, const void *val)
+{
+	return 0;
+}
+
+static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
+			      struct kvm_io_device *this,
+			      gpa_t addr, int len, void *val)
+{
+	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
+		vcpu->vcpu_id, (unsigned long long)addr);
+	return 0;
+}
+
+static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
+			       struct kvm_io_device *this,
+			       gpa_t addr, int len, const void *val)
+{
+	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
+		vcpu->vcpu_id, (unsigned long long)addr);
+	return 0;
+}
+
+struct vgic_register_region vgic_v2_dist_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
+		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+};
+
+int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
+				  struct vgic_register_region *reg_desc,
+				  struct vgic_io_device *region,
+				  int nr_irqs, bool offset_private)
+{
+	int bpi = reg_desc->bits_per_irq;
+	int offset = 0;
+	int len, ret;
+
+	region->base_addr	+= reg_desc->reg_offset;
+	region->redist_vcpu	= vcpu;
+
+	kvm_iodevice_init(&region->dev, &reg_desc->ops);
+
+	if (bpi) {
+		len = (bpi * nr_irqs) / 8;
+		if (offset_private)
+			offset = (bpi * VGIC_NR_PRIVATE_IRQS) / 8;
+	} else {
+		len = reg_desc->len;
+	}
+
+	mutex_lock(&kvm->slots_lock);
+	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+				      region->base_addr + offset,
+				      len - offset, &region->dev);
+	mutex_unlock(&kvm->slots_lock);
+
+	return ret;
+}
+
+int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
+			       enum vgic_type type)
+{
+	struct vgic_io_device *regions;
+	struct vgic_register_region *reg_desc;
+	int nr_regions;
+	int nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+	int i;
+	int ret = 0;
+
+	switch (type) {
+	case VGIC_V2:
+		reg_desc = vgic_v2_dist_registers;
+		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+		break;
+	default:
+		BUG_ON(1);
+	}
+
+	regions = kmalloc_array(nr_regions, sizeof(struct vgic_io_device),
+				GFP_KERNEL);
+	if (!regions)
+		return -ENOMEM;
+
+	for (i = 0; i < nr_regions; i++) {
+		regions[i].base_addr	= dist_base_address;
+
+		ret = kvm_vgic_register_mmio_region(kvm, NULL, reg_desc,
+						    regions + i, nr_irqs,
+						    type == VGIC_V3);
+		if (ret)
+			break;
+
+		reg_desc++;
+	}
+
+	if (ret) {
+		mutex_lock(&kvm->slots_lock);
+		for (i--; i >= 0; i--)
+			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+						  &regions[i].dev);
+		mutex_unlock(&kvm->slots_lock);
+	} else {
+		kvm->arch.vgic.dist_iodevs = regions;
+	}
+
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic_mmio.h b/virt/kvm/arm/vgic/vgic_mmio.h
new file mode 100644
index 0000000..cf2314c
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_mmio.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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_ARM_VGIC_MMIO_H__
+#define __KVM_ARM_VGIC_MMIO_H__
+
+struct vgic_register_region {
+	int reg_offset;
+	int len;
+	int bits_per_irq;
+	struct kvm_io_device_ops ops;
+};
+
+#define REGISTER_DESC_WITH_BITS_PER_IRQ(name, read_ops, write_ops, bpi) \
+	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
+	 .ops.read = read_ops, .ops.write = write_ops}
+#define REGISTER_DESC_WITH_LENGTH(name, read_ops, write_ops, length) \
+	{.reg_offset = name, .bits_per_irq = 0, .len = length, \
+	 .ops.read = read_ops, .ops.write = write_ops}
+
+int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+		       gpa_t addr, int len, void *val);
+int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+		       gpa_t addr, int len, const void *val);
+int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
+				  struct vgic_register_region *reg_desc,
+				  struct vgic_io_device *region,
+				  int nr_irqs, bool offset_private);
+
+void write_mask32(u32 value, int offset, int len, void *val);
+void write_mask64(u64 value, int offset, int len, void *val);
+u32 mask32(u32 origvalue, int offset, int len, const void *val);
+u64 mask64(u64 origvalue, int offset, int len, const void *val);
+
+#endif
-- 
2.7.3

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

* [RFC PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: kvmarm, kvm, linux-arm-kernel

Userland can access the emulated GIC to save and restore its state
for initialization or migration purposes.
The kvm_io_bus API requires an absolute gpa, which does not fit the
KVM_DEV_ARM_VGIC_GRP_DIST_REGS user API, that only provides relative
offsets. So we explicitly iterate our register list to connect
userland to the VGIC.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
 virt/kvm/arm/vgic/vgic.h      |  2 ++
 virt/kvm/arm/vgic/vgic_mmio.c | 45 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 53730ba..a462e2b 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -25,6 +25,8 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
 void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+			int offset, int len, void *val);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 26c46e7..e1fd17f 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -113,6 +113,51 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
 };
 
+/*
+ * Using kvm_io_bus_* to access GIC registers directly from userspace does
+ * not work, since we would need the absolute IPA address of the register
+ * in question, but the userland interface only provides relative offsets.
+ * So we provide our own dispatcher function for that purpose here.
+ */
+static int vgic_mmio_access(struct kvm_vcpu *vcpu,
+			    struct vgic_register_region *region, int nr_regions,
+			    bool is_write, int offset, int len, void *val)
+{
+	int i;
+	struct vgic_io_device dev;
+
+	for (i = 0; i < nr_regions; i++) {
+		int reg_size = region[i].len;
+
+		if (!reg_size)
+			reg_size = (region[i].bits_per_irq * 1024) / 8;
+
+		if ((offset < region[i].reg_offset) ||
+		    (offset + len > region[i].reg_offset + reg_size))
+			continue;
+
+		dev.base_addr	= region[i].reg_offset;
+		dev.redist_vcpu	= vcpu;
+
+		if (is_write)
+			return region[i].ops.write(vcpu, &dev.dev,
+						   offset, len, val);
+		else
+			return region[i].ops.read(vcpu, &dev.dev,
+						  offset, len, val);
+	}
+
+	return -ENODEV;
+}
+
+int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+			int offset, int len, void *val)
+{
+	return vgic_mmio_access(vcpu, vgic_v2_dist_registers,
+				ARRAY_SIZE(vgic_v2_dist_registers),
+				is_write, offset, len, val);
+}
+
 int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
 				  struct vgic_register_region *reg_desc,
 				  struct vgic_io_device *region,
-- 
2.7.3


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

* [RFC PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Userland can access the emulated GIC to save and restore its state
for initialization or migration purposes.
The kvm_io_bus API requires an absolute gpa, which does not fit the
KVM_DEV_ARM_VGIC_GRP_DIST_REGS user API, that only provides relative
offsets. So we explicitly iterate our register list to connect
userland to the VGIC.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
 virt/kvm/arm/vgic/vgic.h      |  2 ++
 virt/kvm/arm/vgic/vgic_mmio.c | 45 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 53730ba..a462e2b 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -25,6 +25,8 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
 void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+			int offset, int len, void *val);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 26c46e7..e1fd17f 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -113,6 +113,51 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
 };
 
+/*
+ * Using kvm_io_bus_* to access GIC registers directly from userspace does
+ * not work, since we would need the absolute IPA address of the register
+ * in question, but the userland interface only provides relative offsets.
+ * So we provide our own dispatcher function for that purpose here.
+ */
+static int vgic_mmio_access(struct kvm_vcpu *vcpu,
+			    struct vgic_register_region *region, int nr_regions,
+			    bool is_write, int offset, int len, void *val)
+{
+	int i;
+	struct vgic_io_device dev;
+
+	for (i = 0; i < nr_regions; i++) {
+		int reg_size = region[i].len;
+
+		if (!reg_size)
+			reg_size = (region[i].bits_per_irq * 1024) / 8;
+
+		if ((offset < region[i].reg_offset) ||
+		    (offset + len > region[i].reg_offset + reg_size))
+			continue;
+
+		dev.base_addr	= region[i].reg_offset;
+		dev.redist_vcpu	= vcpu;
+
+		if (is_write)
+			return region[i].ops.write(vcpu, &dev.dev,
+						   offset, len, val);
+		else
+			return region[i].ops.read(vcpu, &dev.dev,
+						  offset, len, val);
+	}
+
+	return -ENODEV;
+}
+
+int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+			int offset, int len, void *val)
+{
+	return vgic_mmio_access(vcpu, vgic_v2_dist_registers,
+				ARRAY_SIZE(vgic_v2_dist_registers),
+				is_write, offset, len, val);
+}
+
 int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
 				  struct vgic_register_region *reg_desc,
 				  struct vgic_io_device *region,
-- 
2.7.3

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

* [RFC PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.h      |  3 +++
 virt/kvm/arm/vgic/vgic_mmio.c | 49 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index a462e2b..57aea8f 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -16,6 +16,9 @@
 #ifndef __KVM_ARM_VGIC_NEW_H__
 #define __KVM_ARM_VGIC_NEW_H__
 
+#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
+#define IMPLEMENTER_ARM		0x43b
+
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index e1fd17f..e62366e 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -82,9 +82,56 @@ static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 value;
+
+	switch ((addr - iodev->base_addr) & ~3) {
+	case 0x0:
+		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
+		break;
+	case 0x4:
+		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+		value = (value >> 5) - 1;
+		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
+		break;
+	case 0x8:
+		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+		break;
+	default:
+		return 0;
+	}
+
+	write_mask32(value, addr & 3, len, val);
+	return 0;
+}
+
+static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	/*
+	 * GICD_TYPER and GICD_IIDR are read-only, the upper three bytes of
+	 * GICD_CTLR are reserved.
+	 */
+	if (addr - iodev->base_addr >= 1)
+		return 0;
+
+	vcpu->kvm->arch.vgic.enabled = (*(u32 *)val) ? true : false;
+	/* TODO: is there anything to trigger at this point? */
+
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
+		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
-- 
2.7.3

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

* [RFC PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.h      |  3 +++
 virt/kvm/arm/vgic/vgic_mmio.c | 49 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index a462e2b..57aea8f 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -16,6 +16,9 @@
 #ifndef __KVM_ARM_VGIC_NEW_H__
 #define __KVM_ARM_VGIC_NEW_H__
 
+#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
+#define IMPLEMENTER_ARM		0x43b
+
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index e1fd17f..e62366e 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -82,9 +82,56 @@ static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 value;
+
+	switch ((addr - iodev->base_addr) & ~3) {
+	case 0x0:
+		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
+		break;
+	case 0x4:
+		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+		value = (value >> 5) - 1;
+		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
+		break;
+	case 0x8:
+		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+		break;
+	default:
+		return 0;
+	}
+
+	write_mask32(value, addr & 3, len, val);
+	return 0;
+}
+
+static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	/*
+	 * GICD_TYPER and GICD_IIDR are read-only, the upper three bytes of
+	 * GICD_CTLR are reserved.
+	 */
+	if (addr - iodev->base_addr >= 1)
+		return 0;
+
+	vcpu->kvm->arch.vgic.enabled = (*(u32 *)val) ? true : false;
+	/* TODO: is there anything to trigger at this point? */
+
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
+		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
-- 
2.7.3

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

* [RFC PATCH 15/45] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: kvmarm, kvm, linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 81 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index e62366e..0688a69 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -129,15 +129,92 @@ static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+/*
+ * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
+ * of the enabled bit, so there is only one function for both here.
+ */
+static int vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
+				 struct kvm_io_device *this,
+				 gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	u32 value = 0;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->enabled)
+			value |= (1U << i);
+	}
+
+	write_mask32(value, addr & 3, len, val);
+	return 0;
+}
+
+static int vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->enabled = true;
+		vgic_queue_irq(vcpu->kvm, irq);
+	}
+
+	return 0;
+}
+
+static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->enabled = false;
+		/* TODO: Does the exit/entry code take care of "unqueuing"? */
+
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
-- 
2.7.3


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

* [RFC PATCH 15/45] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 81 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index e62366e..0688a69 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -129,15 +129,92 @@ static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+/*
+ * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
+ * of the enabled bit, so there is only one function for both here.
+ */
+static int vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
+				 struct kvm_io_device *this,
+				 gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	u32 value = 0;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->enabled)
+			value |= (1U << i);
+	}
+
+	write_mask32(value, addr & 3, len, val);
+	return 0;
+}
+
+static int vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->enabled = true;
+		vgic_queue_irq(vcpu->kvm, irq);
+	}
+
+	return 0;
+}
+
+static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->enabled = false;
+		/* TODO: Does the exit/entry code take care of "unqueuing"? */
+
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
-- 
2.7.3

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

* [RFC PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 87 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 85 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 0688a69..8514f92 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -206,6 +206,89 @@ static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	u32 value = 0;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		if (irq->pending)
+			value |= (1U << i);
+		spin_unlock(&irq->irq_lock);
+	}
+
+	write_mask32(value, addr & 3, len, val);
+	return 0;
+}
+
+static int vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			irq->soft_pending = true;
+
+		vgic_queue_irq(vcpu->kvm, irq);
+	}
+
+	return 0;
+}
+
+static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		if (irq->config == VGIC_CONFIG_LEVEL) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		} else {
+			irq->pending = false;
+		}
+		/* TODO: Does the exit/entry code take care of "unqueuing"? */
+
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -216,9 +299,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
 		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
-- 
2.7.3

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

* [RFC PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 87 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 85 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 0688a69..8514f92 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -206,6 +206,89 @@ static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	u32 value = 0;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		if (irq->pending)
+			value |= (1U << i);
+		spin_unlock(&irq->irq_lock);
+	}
+
+	write_mask32(value, addr & 3, len, val);
+	return 0;
+}
+
+static int vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			irq->soft_pending = true;
+
+		vgic_queue_irq(vcpu->kvm, irq);
+	}
+
+	return 0;
+}
+
+static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		if (irq->config == VGIC_CONFIG_LEVEL) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		} else {
+			irq->pending = false;
+		}
+		/* TODO: Does the exit/entry code take care of "unqueuing"? */
+
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -216,9 +299,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
 		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
-- 
2.7.3

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

* [RFC PATCH 17/45] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 46 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 8514f92..788e186 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -289,6 +289,50 @@ static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		((u8 *)val)[i] = irq->priority;
+	}
+
+	return 0;
+}
+
+static int vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->priority = ((u8 *)val)[i];
+		spin_unlock(&irq->irq_lock);
+	}
+
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -307,7 +351,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
-- 
2.7.3

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

* [RFC PATCH 17/45] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 46 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 8514f92..788e186 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -289,6 +289,50 @@ static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		((u8 *)val)[i] = irq->priority;
+	}
+
+	return 0;
+}
+
+static int vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->priority = ((u8 *)val)[i];
+		spin_unlock(&irq->irq_lock);
+	}
+
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -307,7 +351,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
-- 
2.7.3

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

* [RFC PATCH 18/45] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 81 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 788e186..bfc530c 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -289,6 +289,83 @@ static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_active(struct kvm_vcpu *vcpu,
+				 struct kvm_io_device *this,
+				 gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	u32 value = 0;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		if (irq->active)
+			value |= (1U << i);
+		spin_unlock(&irq->irq_lock);
+	}
+
+	write_mask32(value, addr & 3, len, val);
+	return 0;
+}
+
+static int vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->active = false;
+		/* TODO: Anything more to do? Does flush/sync cover this? */
+
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
+static int vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->active = true;
+		/* TODO: Anything more to do? Does flush/sync cover this? */
+
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
 static int vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
 				   struct kvm_io_device *this,
 				   gpa_t addr, int len, void *val)
@@ -347,9 +424,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
 		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
 		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
-- 
2.7.3

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

* [RFC PATCH 18/45] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 81 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 788e186..bfc530c 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -289,6 +289,83 @@ static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_active(struct kvm_vcpu *vcpu,
+				 struct kvm_io_device *this,
+				 gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	u32 value = 0;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		if (irq->active)
+			value |= (1U << i);
+		spin_unlock(&irq->irq_lock);
+	}
+
+	write_mask32(value, addr & 3, len, val);
+	return 0;
+}
+
+static int vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->active = false;
+		/* TODO: Anything more to do? Does flush/sync cover this? */
+
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
+static int vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 8;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for_each_set_bit(i, val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->active = true;
+		/* TODO: Anything more to do? Does flush/sync cover this? */
+
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
 static int vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
 				   struct kvm_io_device *this,
 				   gpa_t addr, int len, void *val)
@@ -347,9 +424,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
 		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
 		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
-- 
2.7.3

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

* [RFC PATCH 19/45] KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 63 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 62 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index bfc530c..76657ce 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -410,6 +410,67 @@ static int vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_config(struct kvm_vcpu *vcpu,
+				 struct kvm_io_device *this,
+				 gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 4;
+	u32 value = 0;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for (i = 0; i < len * 4; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			value |= (2U << (i * 2));
+	}
+
+	write_mask32(value, addr & 3, len, val);
+	return 0;
+}
+
+static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 4;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for (i = 0; i < len * 4; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (intid + i < 16)
+			continue;
+
+		/*
+		 * The spec says that interrupts must be disabled before
+		 * changing the configuration to avoid UNDEFINED behaviour.
+		 * Is this sufficient in our case? Do we quickly enough remove
+		 * the IRQ from the ap_list to safely do the config change?
+		 * Will even a disabled interrupt in an ap_list cause us
+		 * headaches if we change the configuration?
+		 */
+		spin_lock(&irq->irq_lock);
+		if (test_bit(i * 2 + 1, val))
+			irq->config = VGIC_CONFIG_EDGE;
+		else
+			irq->config = VGIC_CONFIG_LEVEL;
+		spin_unlock(&irq->irq_lock);
+	}
+
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -432,7 +493,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
-- 
2.7.3

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

* [RFC PATCH 19/45] KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 63 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 62 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index bfc530c..76657ce 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -410,6 +410,67 @@ static int vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_config(struct kvm_vcpu *vcpu,
+				 struct kvm_io_device *this,
+				 gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 4;
+	u32 value = 0;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for (i = 0; i < len * 4; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			value |= (2U << (i * 2));
+	}
+
+	write_mask32(value, addr & 3, len, val);
+	return 0;
+}
+
+static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr) * 4;
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for (i = 0; i < len * 4; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (intid + i < 16)
+			continue;
+
+		/*
+		 * The spec says that interrupts must be disabled before
+		 * changing the configuration to avoid UNDEFINED behaviour.
+		 * Is this sufficient in our case? Do we quickly enough remove
+		 * the IRQ from the ap_list to safely do the config change?
+		 * Will even a disabled interrupt in an ap_list cause us
+		 * headaches if we change the configuration?
+		 */
+		spin_lock(&irq->irq_lock);
+		if (test_bit(i * 2 + 1, val))
+			irq->config = VGIC_CONFIG_EDGE;
+		else
+			irq->config = VGIC_CONFIG_LEVEL;
+		spin_unlock(&irq->irq_lock);
+	}
+
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -432,7 +493,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
-- 
2.7.3

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

* [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 76657ce..cde153f 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
+				 struct kvm_io_device *this,
+				 gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		((u8 *)val)[i] = irq->targets;
+	}
+
+	return 0;
+}
+
+static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	/* GICD_ITARGETSR[0-7] are read-only */
+	if (intid < VGIC_NR_PRIVATE_IRQS)
+		return 0;
+
+	for (i = 0; i < len; i++)
+		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
+					    ((u8 *)val)[i]);
+
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -491,7 +532,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
 		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+		vgic_mmio_read_target, vgic_mmio_write_target, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
-- 
2.7.3

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

* [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 76657ce..cde153f 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
+				 struct kvm_io_device *this,
+				 gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	if (iodev->redist_vcpu)
+		vcpu = iodev->redist_vcpu;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		((u8 *)val)[i] = irq->targets;
+	}
+
+	return 0;
+}
+
+static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	/* GICD_ITARGETSR[0-7] are read-only */
+	if (intid < VGIC_NR_PRIVATE_IRQS)
+		return 0;
+
+	for (i = 0; i < len; i++)
+		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
+					    ((u8 *)val)[i]);
+
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -491,7 +532,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
 		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+		vgic_mmio_read_target, vgic_mmio_write_target, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
-- 
2.7.3

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

* [RFC PATCH 21/45] KVM: arm/arm64: vgic-new: Add SGIR register handler
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 46 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index cde153f..a49726f 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -512,6 +512,50 @@ static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
+				struct kvm_io_device *this,
+				gpa_t addr, int len, const void *val)
+{
+	int nr_vcpus = atomic_read(&source_vcpu->kvm->online_vcpus);
+	u32 value = *(u32 *)val;
+	int intid = value & 0xf;
+	int targets = (value >> 16) & 0xff;
+	int mode = (value >> 24) & 0x03;
+	int c;
+	struct kvm_vcpu *vcpu;
+
+	switch (mode) {
+	case 0x0:		/* as specified by targets */
+		break;
+	case 0x1:
+		targets = (1U << nr_vcpus) - 1;			/* all, ... */
+		targets &= ~(1U << source_vcpu->vcpu_id);	/* but self */
+		break;
+	case 0x2:		/* this very vCPU only */
+		targets = (1U << source_vcpu->vcpu_id);
+		break;
+	case 0x3:		/* reserved */
+		break;
+	}
+
+	kvm_for_each_vcpu(c, vcpu, source_vcpu->kvm) {
+		struct vgic_irq *irq;
+
+		if (!(targets & (1U << c)))
+			continue;
+
+		irq = vgic_get_irq(source_vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+		irq->source |= 1U << source_vcpu->vcpu_id;
+
+		vgic_queue_irq(source_vcpu->kvm, irq);
+	}
+
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -536,7 +580,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
+		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
-- 
2.7.3

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

* [RFC PATCH 21/45] KVM: arm/arm64: vgic-new: Add SGIR register handler
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 46 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index cde153f..a49726f 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -512,6 +512,50 @@ static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static int vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
+				struct kvm_io_device *this,
+				gpa_t addr, int len, const void *val)
+{
+	int nr_vcpus = atomic_read(&source_vcpu->kvm->online_vcpus);
+	u32 value = *(u32 *)val;
+	int intid = value & 0xf;
+	int targets = (value >> 16) & 0xff;
+	int mode = (value >> 24) & 0x03;
+	int c;
+	struct kvm_vcpu *vcpu;
+
+	switch (mode) {
+	case 0x0:		/* as specified by targets */
+		break;
+	case 0x1:
+		targets = (1U << nr_vcpus) - 1;			/* all, ... */
+		targets &= ~(1U << source_vcpu->vcpu_id);	/* but self */
+		break;
+	case 0x2:		/* this very vCPU only */
+		targets = (1U << source_vcpu->vcpu_id);
+		break;
+	case 0x3:		/* reserved */
+		break;
+	}
+
+	kvm_for_each_vcpu(c, vcpu, source_vcpu->kvm) {
+		struct vgic_irq *irq;
+
+		if (!(targets & (1U << c)))
+			continue;
+
+		irq = vgic_get_irq(source_vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+		irq->source |= 1U << source_vcpu->vcpu_id;
+
+		vgic_queue_irq(source_vcpu->kvm, irq);
+	}
+
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -536,7 +580,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
+		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
 		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
-- 
2.7.3

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

* [RFC PATCH 22/45] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Signed-off-by: Andre Przywara <andre.przywara@arm.com>

---
 virt/kvm/arm/vgic/vgic_mmio.c | 79 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 59 insertions(+), 20 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index a49726f..2ab8961 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -64,24 +64,6 @@ int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
 	return 0;
 }
 
-static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
-			      struct kvm_io_device *this,
-			      gpa_t addr, int len, void *val)
-{
-	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
-		vcpu->vcpu_id, (unsigned long long)addr);
-	return 0;
-}
-
-static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
-			       struct kvm_io_device *this,
-			       gpa_t addr, int len, const void *val)
-{
-	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
-		vcpu->vcpu_id, (unsigned long long)addr);
-	return 0;
-}
-
 static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
 				  struct kvm_io_device *this,
 				  gpa_t addr, int len, void *val)
@@ -556,6 +538,63 @@ static int vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		((u8 *)val)[i] = irq->source;
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
+static int vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->source &= ~((u8 *)val)[i];
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
+static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->source |= ((u8 *)val)[i];
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -582,9 +621,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
 		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+		vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
 };
 
 /*
-- 
2.7.3

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

* [RFC PATCH 22/45] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>

---
 virt/kvm/arm/vgic/vgic_mmio.c | 79 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 59 insertions(+), 20 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index a49726f..2ab8961 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -64,24 +64,6 @@ int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
 	return 0;
 }
 
-static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
-			      struct kvm_io_device *this,
-			      gpa_t addr, int len, void *val)
-{
-	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
-		vcpu->vcpu_id, (unsigned long long)addr);
-	return 0;
-}
-
-static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
-			       struct kvm_io_device *this,
-			       gpa_t addr, int len, const void *val)
-{
-	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
-		vcpu->vcpu_id, (unsigned long long)addr);
-	return 0;
-}
-
 static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
 				  struct kvm_io_device *this,
 				  gpa_t addr, int len, void *val)
@@ -556,6 +538,63 @@ static int vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
 	return 0;
 }
 
+static int vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		((u8 *)val)[i] = irq->source;
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
+static int vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->source &= ~((u8 *)val)[i];
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
+static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 intid = (addr - iodev->base_addr);
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->source |= ((u8 *)val)[i];
+		spin_unlock(&irq->irq_lock);
+	}
+	return 0;
+}
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -582,9 +621,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
 		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+		vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
-		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
 };
 
 /*
-- 
2.7.3

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

* [RFC PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Describe the GICv3 distributor and redistributor registers in our
structure. This adds a special macro to deal with the split of
SGI/PPI in the redistributor and SPIs in the distributor, which
allows us to reuse the existing GICv2 handlers for those registers
which are compatible.
Also we register the separate MMIO page for the redistributor
registers dealing with private interrupts.
GICv3 specific registers are only implemented as stubs at this time.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.h      |  16 +++
 virt/kvm/arm/vgic/vgic_mmio.c | 246 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 262 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 57aea8f..4b8952a 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -37,6 +37,10 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
 void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+			int offset, int len, void *val);
+int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
+			  int offset, int len, void *val);
 #else
 static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
 					       u64 mpidr)
@@ -59,6 +63,18 @@ static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
 static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
 }
+
+static inline int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+				      int offset, int len, void *val)
+{
+	return -ENXIO;
+}
+
+static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
+					int offset, int len, void *val)
+{
+	return -ENXIO;
+}
 #endif
 
 #endif
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 2ab8961..2d10c06 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -17,6 +17,8 @@
 #include <kvm/vgic/vgic.h>
 #include <linux/bitops.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/irqchip/arm-gic-v3.h>
+#include <asm/kvm_emulate.h>
 
 #include "vgic.h"
 #include "vgic_mmio.h"
@@ -595,6 +597,105 @@ static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+/*****************************/
+/* GICv3 emulation functions */
+/*****************************/
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+
+static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_read_v3r_misc(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, void *val)
+{
+	/* TODO: implement for ITS support */
+	return vgic_mmio_read_raz(vcpu, this, addr, len, val);
+}
+
+static int vgic_mmio_write_v3r_misc(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	/* TODO: implement for ITS support */
+	return vgic_mmio_write_wi(vcpu, this, addr, len, val);
+}
+
+static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, void *val)
+{
+	return 0;
+}
+
+static int vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_read_v3r_propbase(struct kvm_vcpu *vcpu,
+				       struct kvm_io_device *this,
+				       gpa_t addr, int len, void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_write_v3r_propbase(struct kvm_vcpu *vcpu,
+				        struct kvm_io_device *this,
+				        gpa_t addr, int len, const void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_read_v3r_pendbase(struct kvm_vcpu *vcpu,
+				       struct kvm_io_device *this,
+				       gpa_t addr, int len, void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_write_v3r_pendbase(struct kvm_vcpu *vcpu,
+				        struct kvm_io_device *this,
+				        gpa_t addr, int len, const void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+#endif
+
+/*
+ * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
+ * redistributors, while SPIs are covered by registers in the distributor
+ * block. Trying to set private IRQs in this block gets ignored.
+ * We take some special care here to fix the calculation of the register
+ * offset.
+ */
+#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(name, read_ops, write_ops, bpi) \
+	{.reg_offset = name, .bits_per_irq = 0, \
+	 .len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
+	 .ops.read = vgic_mmio_read_raz, .ops.write = vgic_mmio_write_wi, }, \
+	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
+	 .ops.read = read_ops, .ops.write = write_ops, }
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -626,6 +727,73 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
 };
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+struct vgic_register_region vgic_v3_dist_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
+		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
+		vgic_mmio_read_config, vgic_mmio_write_config, 2),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+};
+
+struct vgic_register_region vgic_v3_redist_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
+		vgic_mmio_read_v3r_misc, vgic_mmio_write_v3r_misc, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
+		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
+		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
+		vgic_mmio_read_v3r_propbase, vgic_mmio_write_v3r_propbase, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
+		vgic_mmio_read_v3r_pendbase, vgic_mmio_write_v3r_pendbase, 8),
+};
+
+struct vgic_register_region vgic_v3_private_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
+		vgic_mmio_read_config, vgic_mmio_write_config, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+};
+#endif
+
 /*
  * Using kvm_io_bus_* to access GIC registers directly from userspace does
  * not work, since we would need the absolute IPA address of the register
@@ -671,6 +839,24 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 				is_write, offset, len, val);
 }
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+			int offset, int len, void *val)
+{
+	return vgic_mmio_access(vcpu, vgic_v3_dist_registers,
+				ARRAY_SIZE(vgic_v3_dist_registers),
+				is_write, offset, len, val);
+}
+
+int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
+			  int offset, int len, void *val)
+{
+	return vgic_mmio_access(vcpu, vgic_v3_redist_registers,
+				ARRAY_SIZE(vgic_v3_redist_registers),
+				is_write, offset, len, val);
+}
+#endif
+
 int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
 				  struct vgic_register_region *reg_desc,
 				  struct vgic_io_device *region,
@@ -717,6 +903,12 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
 		reg_desc = vgic_v2_dist_registers;
 		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
 		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case VGIC_V3:
+		reg_desc = vgic_v3_dist_registers;
+		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
+		break;
+#endif
 	default:
 		BUG_ON(1);
 	}
@@ -750,3 +942,57 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
 
 	return ret;
 }
+
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
+{
+	int nr_vcpus = atomic_read(&kvm->online_vcpus);
+	int nr_regions = ARRAY_SIZE(vgic_v3_redist_registers) +
+			 ARRAY_SIZE(vgic_v3_private_registers);
+	struct kvm_vcpu *vcpu;
+	struct vgic_io_device *regions, *region;
+	int c, i, ret = 0;
+
+	regions = kmalloc(sizeof(struct vgic_io_device) * nr_regions * nr_vcpus,
+			  GFP_KERNEL);
+	if (!regions)
+		return -ENOMEM;
+
+	kvm_for_each_vcpu(c, vcpu, kvm) {
+		region = &regions[c * nr_regions];
+		for (i = 0; i < ARRAY_SIZE(vgic_v3_redist_registers); i++) {
+			region->base_addr = redist_base_address;
+			region->base_addr += c * 2 * SZ_64K;
+
+			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
+						vgic_v3_redist_registers + i,
+						region, VGIC_NR_PRIVATE_IRQS,
+						false);
+			if (ret)
+				break;
+			region++;
+		}
+		if (ret)
+			break;
+
+		for (i = 0; i < ARRAY_SIZE(vgic_v3_private_registers); i++) {
+			region->base_addr = redist_base_address;
+			region->base_addr += c * 2 * SZ_64K + SZ_64K;
+			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
+						vgic_v3_private_registers + i,
+						region, VGIC_NR_PRIVATE_IRQS,
+						false);
+			if (ret)
+				break;
+			region++;
+		}
+		if (ret)
+			break;
+	}
+
+	if (!ret)
+		kvm->arch.vgic.redist_iodevs = regions;
+
+	return ret;
+}
+#endif
-- 
2.7.3

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

* [RFC PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Describe the GICv3 distributor and redistributor registers in our
structure. This adds a special macro to deal with the split of
SGI/PPI in the redistributor and SPIs in the distributor, which
allows us to reuse the existing GICv2 handlers for those registers
which are compatible.
Also we register the separate MMIO page for the redistributor
registers dealing with private interrupts.
GICv3 specific registers are only implemented as stubs at this time.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.h      |  16 +++
 virt/kvm/arm/vgic/vgic_mmio.c | 246 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 262 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 57aea8f..4b8952a 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -37,6 +37,10 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
 void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+			int offset, int len, void *val);
+int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
+			  int offset, int len, void *val);
 #else
 static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
 					       u64 mpidr)
@@ -59,6 +63,18 @@ static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
 static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
 }
+
+static inline int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+				      int offset, int len, void *val)
+{
+	return -ENXIO;
+}
+
+static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
+					int offset, int len, void *val)
+{
+	return -ENXIO;
+}
 #endif
 
 #endif
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 2ab8961..2d10c06 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -17,6 +17,8 @@
 #include <kvm/vgic/vgic.h>
 #include <linux/bitops.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/irqchip/arm-gic-v3.h>
+#include <asm/kvm_emulate.h>
 
 #include "vgic.h"
 #include "vgic_mmio.h"
@@ -595,6 +597,105 @@ static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+/*****************************/
+/* GICv3 emulation functions */
+/*****************************/
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+
+static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_read_v3r_misc(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, void *val)
+{
+	/* TODO: implement for ITS support */
+	return vgic_mmio_read_raz(vcpu, this, addr, len, val);
+}
+
+static int vgic_mmio_write_v3r_misc(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, const void *val)
+{
+	/* TODO: implement for ITS support */
+	return vgic_mmio_write_wi(vcpu, this, addr, len, val);
+}
+
+static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, void *val)
+{
+	return 0;
+}
+
+static int vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_read_v3r_propbase(struct kvm_vcpu *vcpu,
+				       struct kvm_io_device *this,
+				       gpa_t addr, int len, void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_write_v3r_propbase(struct kvm_vcpu *vcpu,
+				        struct kvm_io_device *this,
+				        gpa_t addr, int len, const void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_read_v3r_pendbase(struct kvm_vcpu *vcpu,
+				       struct kvm_io_device *this,
+				       gpa_t addr, int len, void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+
+static int vgic_mmio_write_v3r_pendbase(struct kvm_vcpu *vcpu,
+				        struct kvm_io_device *this,
+				        gpa_t addr, int len, const void *val)
+{
+	/* TODO: implement */
+	return 0;
+}
+#endif
+
+/*
+ * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
+ * redistributors, while SPIs are covered by registers in the distributor
+ * block. Trying to set private IRQs in this block gets ignored.
+ * We take some special care here to fix the calculation of the register
+ * offset.
+ */
+#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(name, read_ops, write_ops, bpi) \
+	{.reg_offset = name, .bits_per_irq = 0, \
+	 .len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
+	 .ops.read = vgic_mmio_read_raz, .ops.write = vgic_mmio_write_wi, }, \
+	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
+	 .ops.read = read_ops, .ops.write = write_ops, }
+
 struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -626,6 +727,73 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
 		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
 };
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+struct vgic_register_region vgic_v3_dist_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
+		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
+		vgic_mmio_read_config, vgic_mmio_write_config, 2),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+};
+
+struct vgic_register_region vgic_v3_redist_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
+		vgic_mmio_read_v3r_misc, vgic_mmio_write_v3r_misc, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
+		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
+		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
+		vgic_mmio_read_v3r_propbase, vgic_mmio_write_v3r_propbase, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
+		vgic_mmio_read_v3r_pendbase, vgic_mmio_write_v3r_pendbase, 8),
+};
+
+struct vgic_register_region vgic_v3_private_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
+		vgic_mmio_read_config, vgic_mmio_write_config, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+};
+#endif
+
 /*
  * Using kvm_io_bus_* to access GIC registers directly from userspace does
  * not work, since we would need the absolute IPA address of the register
@@ -671,6 +839,24 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 				is_write, offset, len, val);
 }
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+			int offset, int len, void *val)
+{
+	return vgic_mmio_access(vcpu, vgic_v3_dist_registers,
+				ARRAY_SIZE(vgic_v3_dist_registers),
+				is_write, offset, len, val);
+}
+
+int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
+			  int offset, int len, void *val)
+{
+	return vgic_mmio_access(vcpu, vgic_v3_redist_registers,
+				ARRAY_SIZE(vgic_v3_redist_registers),
+				is_write, offset, len, val);
+}
+#endif
+
 int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
 				  struct vgic_register_region *reg_desc,
 				  struct vgic_io_device *region,
@@ -717,6 +903,12 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
 		reg_desc = vgic_v2_dist_registers;
 		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
 		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case VGIC_V3:
+		reg_desc = vgic_v3_dist_registers;
+		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
+		break;
+#endif
 	default:
 		BUG_ON(1);
 	}
@@ -750,3 +942,57 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
 
 	return ret;
 }
+
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
+{
+	int nr_vcpus = atomic_read(&kvm->online_vcpus);
+	int nr_regions = ARRAY_SIZE(vgic_v3_redist_registers) +
+			 ARRAY_SIZE(vgic_v3_private_registers);
+	struct kvm_vcpu *vcpu;
+	struct vgic_io_device *regions, *region;
+	int c, i, ret = 0;
+
+	regions = kmalloc(sizeof(struct vgic_io_device) * nr_regions * nr_vcpus,
+			  GFP_KERNEL);
+	if (!regions)
+		return -ENOMEM;
+
+	kvm_for_each_vcpu(c, vcpu, kvm) {
+		region = &regions[c * nr_regions];
+		for (i = 0; i < ARRAY_SIZE(vgic_v3_redist_registers); i++) {
+			region->base_addr = redist_base_address;
+			region->base_addr += c * 2 * SZ_64K;
+
+			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
+						vgic_v3_redist_registers + i,
+						region, VGIC_NR_PRIVATE_IRQS,
+						false);
+			if (ret)
+				break;
+			region++;
+		}
+		if (ret)
+			break;
+
+		for (i = 0; i < ARRAY_SIZE(vgic_v3_private_registers); i++) {
+			region->base_addr = redist_base_address;
+			region->base_addr += c * 2 * SZ_64K + SZ_64K;
+			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
+						vgic_v3_private_registers + i,
+						region, VGIC_NR_PRIVATE_IRQS,
+						false);
+			if (ret)
+				break;
+			region++;
+		}
+		if (ret)
+			break;
+	}
+
+	if (!ret)
+		kvm->arch.vgic.redist_iodevs = regions;
+
+	return ret;
+}
+#endif
-- 
2.7.3

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

* [RFC PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

As in the GICv2 emulation we handle those three registers in one
function.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.h      |  2 ++
 virt/kvm/arm/vgic/vgic_mmio.c | 38 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 4b8952a..0db1abe 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -19,6 +19,8 @@
 #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
 #define IMPLEMENTER_ARM		0x43b
 
+#define INTERRUPT_ID_BITS_SPIS	10
+
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 2d10c06..13e101f 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -606,7 +606,29 @@ static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
 				  struct kvm_io_device *this,
 				  gpa_t addr, int len, void *val)
 {
-	/* TODO: implement */
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 value = 0;
+
+	switch ((addr - iodev->base_addr) & ~3) {
+	case GICD_CTLR:
+		if (vcpu->kvm->arch.vgic.enabled)
+		       value |=	GICD_CTLR_ENABLE_SS_G1;
+		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
+		break;
+	case GICD_TYPER:
+		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+		value = (value >> 5) - 1;
+		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+		break;
+	case GICD_IIDR:
+		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+		break;
+	default:
+		return 0;
+	}
+
+	write_mask32(value, addr & 3, len, val);
 	return 0;
 }
 
@@ -614,7 +636,19 @@ static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
 				   struct kvm_io_device *this,
 				   gpa_t addr, int len, const void *val)
 {
-	/* TODO: implement */
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	bool enabled;
+
+	/* These are not the bits you are looking for ... */
+	if (addr - iodev->base_addr > 0)
+		return 0;
+
+	/* We only care about the enable bit, all other bits are WI. */
+	enabled = *(u8*)val & GICD_CTLR_ENABLE_SS_G1;
+
+	vcpu->kvm->arch.vgic.enabled = enabled;
+
 	return 0;
 }
 
-- 
2.7.3

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

* [RFC PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

As in the GICv2 emulation we handle those three registers in one
function.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.h      |  2 ++
 virt/kvm/arm/vgic/vgic_mmio.c | 38 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 4b8952a..0db1abe 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -19,6 +19,8 @@
 #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
 #define IMPLEMENTER_ARM		0x43b
 
+#define INTERRUPT_ID_BITS_SPIS	10
+
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 2d10c06..13e101f 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -606,7 +606,29 @@ static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
 				  struct kvm_io_device *this,
 				  gpa_t addr, int len, void *val)
 {
-	/* TODO: implement */
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 value = 0;
+
+	switch ((addr - iodev->base_addr) & ~3) {
+	case GICD_CTLR:
+		if (vcpu->kvm->arch.vgic.enabled)
+		       value |=	GICD_CTLR_ENABLE_SS_G1;
+		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
+		break;
+	case GICD_TYPER:
+		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+		value = (value >> 5) - 1;
+		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+		break;
+	case GICD_IIDR:
+		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+		break;
+	default:
+		return 0;
+	}
+
+	write_mask32(value, addr & 3, len, val);
 	return 0;
 }
 
@@ -614,7 +636,19 @@ static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
 				   struct kvm_io_device *this,
 				   gpa_t addr, int len, const void *val)
 {
-	/* TODO: implement */
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	bool enabled;
+
+	/* These are not the bits you are looking for ... */
+	if (addr - iodev->base_addr > 0)
+		return 0;
+
+	/* We only care about the enable bit, all other bits are WI. */
+	enabled = *(u8*)val & GICD_CTLR_ENABLE_SS_G1;
+
+	vcpu->kvm->arch.vgic.enabled = enabled;
+
 	return 0;
 }
 
-- 
2.7.3

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

* [RFC PATCH 25/45] KVM: arm/arm64: vgic-new: Add GICv3 redistributor TYPER handler
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: kvmarm, kvm, linux-arm-kernel

The redistributor TYPER tells the OS about the associated MPIDR,
also the LAST bit is crucial.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 13e101f..6d74b00 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -652,6 +652,22 @@ static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+/*
+ * We use a compressed version of the MPIDR (all 32 bits in one 32-bit word)
+ * when we store the target MPIDR written by the guest.
+ */
+static u32 compress_mpidr(unsigned long mpidr)
+{
+	u32 ret;
+
+	ret = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8;
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16;
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24;
+
+	return ret;
+}
+
 static int vgic_mmio_read_v3r_misc(struct kvm_vcpu *vcpu,
 				   struct kvm_io_device *this,
 				   gpa_t addr, int len, void *val)
@@ -672,6 +688,9 @@ static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
 				   struct kvm_io_device *this,
 				   gpa_t addr, int len, void *val)
 {
+	write_mask32((PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0),
+		     addr & 3, len, val);
+
 	return 0;
 }
 
@@ -679,7 +698,18 @@ static int vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
 				    struct kvm_io_device *this,
 				    gpa_t addr, int len, void *val)
 {
-	/* TODO: implement */
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	unsigned long mpidr = kvm_vcpu_get_mpidr_aff(iodev->redist_vcpu);
+	int target_vcpu_id = iodev->redist_vcpu->vcpu_id;
+	u64 value;
+
+	value = (u64)compress_mpidr(mpidr) << 32;
+	value |= ((target_vcpu_id & 0xffff) << 8);
+	if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
+		value |= GICR_TYPER_LAST;
+
+	write_mask64(value, addr & 7, len, val);
 	return 0;
 }
 
-- 
2.7.3


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

* [RFC PATCH 25/45] KVM: arm/arm64: vgic-new: Add GICv3 redistributor TYPER handler
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

The redistributor TYPER tells the OS about the associated MPIDR,
also the LAST bit is crucial.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_mmio.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 13e101f..6d74b00 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -652,6 +652,22 @@ static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+/*
+ * We use a compressed version of the MPIDR (all 32 bits in one 32-bit word)
+ * when we store the target MPIDR written by the guest.
+ */
+static u32 compress_mpidr(unsigned long mpidr)
+{
+	u32 ret;
+
+	ret = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8;
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16;
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24;
+
+	return ret;
+}
+
 static int vgic_mmio_read_v3r_misc(struct kvm_vcpu *vcpu,
 				   struct kvm_io_device *this,
 				   gpa_t addr, int len, void *val)
@@ -672,6 +688,9 @@ static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
 				   struct kvm_io_device *this,
 				   gpa_t addr, int len, void *val)
 {
+	write_mask32((PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0),
+		     addr & 3, len, val);
+
 	return 0;
 }
 
@@ -679,7 +698,18 @@ static int vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
 				    struct kvm_io_device *this,
 				    gpa_t addr, int len, void *val)
 {
-	/* TODO: implement */
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	unsigned long mpidr = kvm_vcpu_get_mpidr_aff(iodev->redist_vcpu);
+	int target_vcpu_id = iodev->redist_vcpu->vcpu_id;
+	u64 value;
+
+	value = (u64)compress_mpidr(mpidr) << 32;
+	value |= ((target_vcpu_id & 0xffff) << 8);
+	if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
+		value |= GICR_TYPER_LAST;
+
+	write_mask64(value, addr & 7, len, val);
 	return 0;
 }
 
-- 
2.7.3

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

* [RFC PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

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

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 6d74b00..544ba31 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -744,6 +744,26 @@ static int vgic_mmio_write_v3r_pendbase(struct kvm_vcpu *vcpu,
 	/* TODO: implement */
 	return 0;
 }
+
+static int vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 regnr = (addr - iodev->base_addr);
+	u32 reg = 0;
+
+	switch (regnr + GICD_IDREGS) {
+	case GICD_PIDR2:
+		/* report a GICv3 compliant implementation */
+		reg = 0x3b;
+		break;
+	}
+
+	write_mask32(reg , addr & 3, len, val);
+	return 0;
+}
 #endif
 
 /*
@@ -817,6 +837,8 @@ struct vgic_register_region vgic_v3_dist_registers[] = {
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
+		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
 
 struct vgic_register_region vgic_v3_redist_registers[] = {
@@ -830,6 +852,8 @@ struct vgic_register_region vgic_v3_redist_registers[] = {
 		vgic_mmio_read_v3r_propbase, vgic_mmio_write_v3r_propbase, 8),
 	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
 		vgic_mmio_read_v3r_pendbase, vgic_mmio_write_v3r_pendbase, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
+		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
 
 struct vgic_register_region vgic_v3_private_registers[] = {
-- 
2.7.3

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

* [RFC PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

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

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 6d74b00..544ba31 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -744,6 +744,26 @@ static int vgic_mmio_write_v3r_pendbase(struct kvm_vcpu *vcpu,
 	/* TODO: implement */
 	return 0;
 }
+
+static int vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
+				    struct kvm_io_device *this,
+				    gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	u32 regnr = (addr - iodev->base_addr);
+	u32 reg = 0;
+
+	switch (regnr + GICD_IDREGS) {
+	case GICD_PIDR2:
+		/* report a GICv3 compliant implementation */
+		reg = 0x3b;
+		break;
+	}
+
+	write_mask32(reg , addr & 3, len, val);
+	return 0;
+}
 #endif
 
 /*
@@ -817,6 +837,8 @@ struct vgic_register_region vgic_v3_dist_registers[] = {
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
+		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
 
 struct vgic_register_region vgic_v3_redist_registers[] = {
@@ -830,6 +852,8 @@ struct vgic_register_region vgic_v3_redist_registers[] = {
 		vgic_mmio_read_v3r_propbase, vgic_mmio_write_v3r_propbase, 8),
 	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
 		vgic_mmio_read_v3r_pendbase, vgic_mmio_write_v3r_pendbase, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
+		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
 
 struct vgic_register_region vgic_v3_private_registers[] = {
-- 
2.7.3

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

* [RFC PATCH 27/45] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Those set the affinity of a SPI interrupt.

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

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 544ba31..44fdba5 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -668,6 +668,60 @@ static u32 compress_mpidr(unsigned long mpidr)
 	return ret;
 }
 
+static unsigned long decompress_mpidr(u32 value)
+{
+	unsigned long mpidr;
+
+	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
+	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
+	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
+	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
+
+	return mpidr;
+}
+
+static int vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	int intid = (addr - iodev->base_addr) / 8;
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+
+	if (!irq) {
+		memset(val, 0, len);
+		return 0;
+	}
+
+	write_mask64(decompress_mpidr(irq->mpidr), addr & 7, len, val);
+
+	return 0;
+}
+
+static int vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	int intid = (addr - iodev->base_addr) / 8;
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+	u64 mpidr;
+
+	if (!irq)
+		return 0;
+
+	mpidr = decompress_mpidr(irq->mpidr);
+	mpidr = mask64(mpidr, addr & 7, len, val);
+
+	irq->mpidr = compress_mpidr(mpidr);
+
+	vgic_v3_irq_change_affinity(vcpu->kvm, intid, mpidr);
+
+	return 0;
+}
+
 static int vgic_mmio_read_v3r_misc(struct kvm_vcpu *vcpu,
 				   struct kvm_io_device *this,
 				   gpa_t addr, int len, void *val)
@@ -837,6 +891,8 @@ struct vgic_register_region vgic_v3_dist_registers[] = {
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
+		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64),
 	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
 		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
-- 
2.7.3

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

* [RFC PATCH 27/45] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Those set the affinity of a SPI interrupt.

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

diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 544ba31..44fdba5 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -668,6 +668,60 @@ static u32 compress_mpidr(unsigned long mpidr)
 	return ret;
 }
 
+static unsigned long decompress_mpidr(u32 value)
+{
+	unsigned long mpidr;
+
+	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
+	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
+	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
+	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
+
+	return mpidr;
+}
+
+static int vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
+				  struct kvm_io_device *this,
+				  gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	int intid = (addr - iodev->base_addr) / 8;
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+
+	if (!irq) {
+		memset(val, 0, len);
+		return 0;
+	}
+
+	write_mask64(decompress_mpidr(irq->mpidr), addr & 7, len, val);
+
+	return 0;
+}
+
+static int vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
+				   struct kvm_io_device *this,
+				   gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = container_of(this,
+						    struct vgic_io_device, dev);
+	int intid = (addr - iodev->base_addr) / 8;
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+	u64 mpidr;
+
+	if (!irq)
+		return 0;
+
+	mpidr = decompress_mpidr(irq->mpidr);
+	mpidr = mask64(mpidr, addr & 7, len, val);
+
+	irq->mpidr = compress_mpidr(mpidr);
+
+	vgic_v3_irq_change_affinity(vcpu->kvm, intid, mpidr);
+
+	return 0;
+}
+
 static int vgic_mmio_read_v3r_misc(struct kvm_vcpu *vcpu,
 				   struct kvm_io_device *this,
 				   gpa_t addr, int len, void *val)
@@ -837,6 +891,8 @@ struct vgic_register_region vgic_v3_dist_registers[] = {
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
+		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64),
 	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
 		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
-- 
2.7.3

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

* [RFC PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
by a MMIO write, but with a system register write. KVM knows about
that register already, we just need to implement the handler and wire
it up to the core KVM/ARM code.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |   8 ++++
 virt/kvm/arm/vgic/vgic_mmio.c | 101 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index a8262c7..ab5fcc7 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -202,6 +202,14 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
 void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
+#else
+static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
+{
+}
+#endif
+
 /**
  * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
  *
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 44fdba5..7eb6b93 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -1139,4 +1139,105 @@ int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
 
 	return ret;
 }
+
+/*
+ * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
+ * generation register ICC_SGI1R_EL1) with a given VCPU.
+ * If the VCPU's MPIDR matches, return the level0 affinity, otherwise
+ * return -1.
+ */
+static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct kvm_vcpu *vcpu)
+{
+	unsigned long affinity;
+	int level0;
+
+	/*
+	 * Split the current VCPU's MPIDR into affinity level 0 and the
+	 * rest as this is what we have to compare against.
+	 */
+	affinity = kvm_vcpu_get_mpidr_aff(vcpu);
+	level0 = MPIDR_AFFINITY_LEVEL(affinity, 0);
+	affinity &= ~MPIDR_LEVEL_MASK;
+
+	/* bail out if the upper three levels don't match */
+	if (sgi_aff != affinity)
+		return -1;
+
+	/* Is this VCPU's bit set in the mask ? */
+	if (!(sgi_cpu_mask & BIT(level0)))
+		return -1;
+
+	return level0;
+}
+
+#define SGI_AFFINITY_LEVEL(reg, level) \
+	((((reg) & ICC_SGI1R_AFFINITY_## level ##_MASK) \
+	>> ICC_SGI1R_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
+
+/**
+ * vgic_v3_dispatch_sgi - handle SGI requests from VCPUs
+ * @vcpu: The VCPU requesting a SGI
+ * @reg: The value written into the ICC_SGI1R_EL1 register by that VCPU
+ *
+ * With GICv3 (and ARE=1) CPUs trigger SGIs by writing to a system register.
+ * This will trap in sys_regs.c and call this function.
+ * This ICC_SGI1R_EL1 register contains the upper three affinity levels of the
+ * target processors as well as a bitmask of 16 Aff0 CPUs.
+ * If the interrupt routing mode bit is not set, we iterate over all VCPUs to
+ * check for matching ones. If this bit is set, we signal all, but not the
+ * calling VCPU.
+ */
+void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct kvm_vcpu *c_vcpu;
+	u16 target_cpus;
+	u64 mpidr;
+	int sgi, c;
+	int vcpu_id = vcpu->vcpu_id;
+	bool broadcast;
+
+	sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
+	broadcast = reg & BIT(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
+	target_cpus = (reg & ICC_SGI1R_TARGET_LIST_MASK) >> ICC_SGI1R_TARGET_LIST_SHIFT;
+	mpidr = SGI_AFFINITY_LEVEL(reg, 3);
+	mpidr |= SGI_AFFINITY_LEVEL(reg, 2);
+	mpidr |= SGI_AFFINITY_LEVEL(reg, 1);
+
+	/*
+	 * We iterate over all VCPUs to find the MPIDRs matching the request.
+	 * If we have handled one CPU, we clear it's bit to detect early
+	 * if we are already finished. This avoids iterating through all
+	 * VCPUs when most of the times we just signal a single VCPU.
+	 */
+	kvm_for_each_vcpu(c, c_vcpu, kvm) {
+		struct vgic_irq *irq;
+
+		/* Exit early if we have dealt with all requested CPUs */
+		if (!broadcast && target_cpus == 0)
+			break;
+
+		/* Don't signal the calling VCPU */
+		if (broadcast && c == vcpu_id)
+			continue;
+
+		if (!broadcast) {
+			int level0;
+
+			level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
+			if (level0 == -1)
+				continue;
+
+			/* remove this matching VCPU from the mask */
+			target_cpus &= ~BIT(level0);
+		}
+
+		irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+
+		vgic_queue_irq(vcpu->kvm, irq);
+	}
+}
 #endif
-- 
2.7.3

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

* [RFC PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
by a MMIO write, but with a system register write. KVM knows about
that register already, we just need to implement the handler and wire
it up to the core KVM/ARM code.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |   8 ++++
 virt/kvm/arm/vgic/vgic_mmio.c | 101 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index a8262c7..ab5fcc7 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -202,6 +202,14 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
 void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
+#else
+static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
+{
+}
+#endif
+
 /**
  * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
  *
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 44fdba5..7eb6b93 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -1139,4 +1139,105 @@ int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
 
 	return ret;
 }
+
+/*
+ * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
+ * generation register ICC_SGI1R_EL1) with a given VCPU.
+ * If the VCPU's MPIDR matches, return the level0 affinity, otherwise
+ * return -1.
+ */
+static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct kvm_vcpu *vcpu)
+{
+	unsigned long affinity;
+	int level0;
+
+	/*
+	 * Split the current VCPU's MPIDR into affinity level 0 and the
+	 * rest as this is what we have to compare against.
+	 */
+	affinity = kvm_vcpu_get_mpidr_aff(vcpu);
+	level0 = MPIDR_AFFINITY_LEVEL(affinity, 0);
+	affinity &= ~MPIDR_LEVEL_MASK;
+
+	/* bail out if the upper three levels don't match */
+	if (sgi_aff != affinity)
+		return -1;
+
+	/* Is this VCPU's bit set in the mask ? */
+	if (!(sgi_cpu_mask & BIT(level0)))
+		return -1;
+
+	return level0;
+}
+
+#define SGI_AFFINITY_LEVEL(reg, level) \
+	((((reg) & ICC_SGI1R_AFFINITY_## level ##_MASK) \
+	>> ICC_SGI1R_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
+
+/**
+ * vgic_v3_dispatch_sgi - handle SGI requests from VCPUs
+ * @vcpu: The VCPU requesting a SGI
+ * @reg: The value written into the ICC_SGI1R_EL1 register by that VCPU
+ *
+ * With GICv3 (and ARE=1) CPUs trigger SGIs by writing to a system register.
+ * This will trap in sys_regs.c and call this function.
+ * This ICC_SGI1R_EL1 register contains the upper three affinity levels of the
+ * target processors as well as a bitmask of 16 Aff0 CPUs.
+ * If the interrupt routing mode bit is not set, we iterate over all VCPUs to
+ * check for matching ones. If this bit is set, we signal all, but not the
+ * calling VCPU.
+ */
+void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct kvm_vcpu *c_vcpu;
+	u16 target_cpus;
+	u64 mpidr;
+	int sgi, c;
+	int vcpu_id = vcpu->vcpu_id;
+	bool broadcast;
+
+	sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
+	broadcast = reg & BIT(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
+	target_cpus = (reg & ICC_SGI1R_TARGET_LIST_MASK) >> ICC_SGI1R_TARGET_LIST_SHIFT;
+	mpidr = SGI_AFFINITY_LEVEL(reg, 3);
+	mpidr |= SGI_AFFINITY_LEVEL(reg, 2);
+	mpidr |= SGI_AFFINITY_LEVEL(reg, 1);
+
+	/*
+	 * We iterate over all VCPUs to find the MPIDRs matching the request.
+	 * If we have handled one CPU, we clear it's bit to detect early
+	 * if we are already finished. This avoids iterating through all
+	 * VCPUs when most of the times we just signal a single VCPU.
+	 */
+	kvm_for_each_vcpu(c, c_vcpu, kvm) {
+		struct vgic_irq *irq;
+
+		/* Exit early if we have dealt with all requested CPUs */
+		if (!broadcast && target_cpus == 0)
+			break;
+
+		/* Don't signal the calling VCPU */
+		if (broadcast && c == vcpu_id)
+			continue;
+
+		if (!broadcast) {
+			int level0;
+
+			level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
+			if (level0 == -1)
+				continue;
+
+			/* remove this matching VCPU from the mask */
+			target_cpus &= ~BIT(level0);
+		}
+
+		irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+
+		vgic_queue_irq(vcpu->kvm, irq);
+	}
+}
 #endif
-- 
2.7.3

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

* [RFC PATCH 29/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch introduces the skeleton for the KVM device operations
associated to KVM_DEV_TYPE_ARM_VGIC_V2 and KVM_DEV_TYPE_ARM_VGIC_V3.

At that stage kvm_vgic_create is stubbed.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.h            |   2 +
 virt/kvm/arm/vgic/vgic_kvm_device.c | 108 ++++++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic_kvm_device.c

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 0db1abe..072bec1 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -79,4 +79,6 @@ static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
 }
 #endif
 
+void kvm_register_vgic_device(unsigned long type);
+
 #endif
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
new file mode 100644
index 0000000..7c665f9
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -0,0 +1,108 @@
+/*
+ * VGIC: KVM DEVICE API
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@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.
+ */
+#include <linux/kvm_host.h>
+#include <kvm/vgic/vgic.h>
+
+/* common helpers */
+
+static int vgic_create(struct kvm_device *dev, u32 type)
+{
+	return kvm_vgic_create(dev->kvm, type);
+}
+
+static void vgic_destroy(struct kvm_device *dev)
+{
+	kfree(dev);
+}
+
+void kvm_register_vgic_device(unsigned long type)
+{
+	switch (type) {
+	case KVM_DEV_TYPE_ARM_VGIC_V2:
+		kvm_register_device_ops(&kvm_arm_vgic_v2_ops,
+					KVM_DEV_TYPE_ARM_VGIC_V2);
+		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case KVM_DEV_TYPE_ARM_VGIC_V3:
+		kvm_register_device_ops(&kvm_arm_vgic_v3_ops,
+					KVM_DEV_TYPE_ARM_VGIC_V3);
+		break;
+#endif
+	}
+}
+
+/* V2 ops */
+
+static int vgic_v2_set_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v2_get_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v2_has_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v2_ops = {
+	.name = "kvm-arm-vgic-v2",
+	.create = vgic_create,
+	.destroy = vgic_destroy,
+	.set_attr = vgic_v2_set_attr,
+	.get_attr = vgic_v2_get_attr,
+	.has_attr = vgic_v2_has_attr,
+};
+
+/* V3 ops */
+
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+
+static int vgic_v3_set_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v3_get_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v3_has_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v3_ops = {
+	.name = "kvm-arm-vgic-v3",
+	.create = vgic_create,
+	.destroy = vgic_destroy,
+	.set_attr = vgic_v3_set_attr,
+	.get_attr = vgic_v3_get_attr,
+	.has_attr = vgic_v3_has_attr,
+};
+
+#endif /* CONFIG_KVM_ARM_VGIC_V3 */
+
-- 
2.7.3

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

* [RFC PATCH 29/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch introduces the skeleton for the KVM device operations
associated to KVM_DEV_TYPE_ARM_VGIC_V2 and KVM_DEV_TYPE_ARM_VGIC_V3.

At that stage kvm_vgic_create is stubbed.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.h            |   2 +
 virt/kvm/arm/vgic/vgic_kvm_device.c | 108 ++++++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic_kvm_device.c

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 0db1abe..072bec1 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -79,4 +79,6 @@ static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
 }
 #endif
 
+void kvm_register_vgic_device(unsigned long type);
+
 #endif
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
new file mode 100644
index 0000000..7c665f9
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -0,0 +1,108 @@
+/*
+ * VGIC: KVM DEVICE API
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@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.
+ */
+#include <linux/kvm_host.h>
+#include <kvm/vgic/vgic.h>
+
+/* common helpers */
+
+static int vgic_create(struct kvm_device *dev, u32 type)
+{
+	return kvm_vgic_create(dev->kvm, type);
+}
+
+static void vgic_destroy(struct kvm_device *dev)
+{
+	kfree(dev);
+}
+
+void kvm_register_vgic_device(unsigned long type)
+{
+	switch (type) {
+	case KVM_DEV_TYPE_ARM_VGIC_V2:
+		kvm_register_device_ops(&kvm_arm_vgic_v2_ops,
+					KVM_DEV_TYPE_ARM_VGIC_V2);
+		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case KVM_DEV_TYPE_ARM_VGIC_V3:
+		kvm_register_device_ops(&kvm_arm_vgic_v3_ops,
+					KVM_DEV_TYPE_ARM_VGIC_V3);
+		break;
+#endif
+	}
+}
+
+/* V2 ops */
+
+static int vgic_v2_set_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v2_get_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v2_has_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v2_ops = {
+	.name = "kvm-arm-vgic-v2",
+	.create = vgic_create,
+	.destroy = vgic_destroy,
+	.set_attr = vgic_v2_set_attr,
+	.get_attr = vgic_v2_get_attr,
+	.has_attr = vgic_v2_has_attr,
+};
+
+/* V3 ops */
+
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+
+static int vgic_v3_set_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v3_get_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v3_has_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v3_ops = {
+	.name = "kvm-arm-vgic-v3",
+	.create = vgic_create,
+	.destroy = vgic_destroy,
+	.set_attr = vgic_v3_set_attr,
+	.get_attr = vgic_v3_get_attr,
+	.has_attr = vgic_v3_has_attr,
+};
+
+#endif /* CONFIG_KVM_ARM_VGIC_V3 */
+
-- 
2.7.3

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

* [RFC PATCH 30/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_NR_IRQS group. This
modality is supported by both VGIC V2 and V3 KVM device as will be
other groups, hence the introduction of common helpers.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_kvm_device.c | 83 +++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 4 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index 7c665f9..c96549b 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -15,9 +15,69 @@
  */
 #include <linux/kvm_host.h>
 #include <kvm/vgic/vgic.h>
+#include <linux/uaccess.h>
+#include "vgic.h"
 
 /* common helpers */
 
+static int vgic_set_common_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u32 val;
+		int ret = 0;
+
+		if (get_user(val, uaddr))
+			return -EFAULT;
+
+		/*
+		 * We require:
+		 * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs
+		 * - at most 1024 interrupts
+		 * - a multiple of 32 interrupts
+		 */
+		if (val < (VGIC_NR_PRIVATE_IRQS + 32) ||
+		    val > VGIC_MAX_RESERVED ||
+		    (val & 31))
+			return -EINVAL;
+
+		mutex_lock(&dev->kvm->lock);
+
+		if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis)
+			ret = -EBUSY;
+		else
+			dev->kvm->arch.vgic.nr_spis =
+				val - VGIC_NR_PRIVATE_IRQS;
+
+		mutex_unlock(&dev->kvm->lock);
+
+		return ret;
+	}
+	}
+
+	return -ENXIO;
+}
+
+static int vgic_get_common_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	int r = -ENXIO;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+
+		r = put_user(dev->kvm->arch.vgic.nr_spis +
+			     VGIC_NR_PRIVATE_IRQS, uaddr);
+		break;
+	}
+	}
+
+	return r;
+}
+
 static int vgic_create(struct kvm_device *dev, u32 type)
 {
 	return kvm_vgic_create(dev->kvm, type);
@@ -49,18 +109,29 @@ void kvm_register_vgic_device(unsigned long type)
 static int vgic_v2_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	int ret;
+
+	ret = vgic_set_common_attr(dev, attr);
+	return ret;
+
 }
 
 static int vgic_v2_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	int ret;
+
+	ret = vgic_get_common_attr(dev, attr);
+	return ret;
 }
 
 static int vgic_v2_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		return 0;
+	}
 	return -ENXIO;
 }
 
@@ -80,18 +151,22 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
 static int vgic_v3_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	return vgic_set_common_attr(dev, attr);
 }
 
 static int vgic_v3_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	return vgic_get_common_attr(dev, attr);
 }
 
 static int vgic_v3_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		return 0;
+	}
 	return -ENXIO;
 }
 
-- 
2.7.3

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

* [RFC PATCH 30/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_NR_IRQS group. This
modality is supported by both VGIC V2 and V3 KVM device as will be
other groups, hence the introduction of common helpers.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_kvm_device.c | 83 +++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 4 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index 7c665f9..c96549b 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -15,9 +15,69 @@
  */
 #include <linux/kvm_host.h>
 #include <kvm/vgic/vgic.h>
+#include <linux/uaccess.h>
+#include "vgic.h"
 
 /* common helpers */
 
+static int vgic_set_common_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u32 val;
+		int ret = 0;
+
+		if (get_user(val, uaddr))
+			return -EFAULT;
+
+		/*
+		 * We require:
+		 * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs
+		 * - at most 1024 interrupts
+		 * - a multiple of 32 interrupts
+		 */
+		if (val < (VGIC_NR_PRIVATE_IRQS + 32) ||
+		    val > VGIC_MAX_RESERVED ||
+		    (val & 31))
+			return -EINVAL;
+
+		mutex_lock(&dev->kvm->lock);
+
+		if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis)
+			ret = -EBUSY;
+		else
+			dev->kvm->arch.vgic.nr_spis =
+				val - VGIC_NR_PRIVATE_IRQS;
+
+		mutex_unlock(&dev->kvm->lock);
+
+		return ret;
+	}
+	}
+
+	return -ENXIO;
+}
+
+static int vgic_get_common_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	int r = -ENXIO;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+
+		r = put_user(dev->kvm->arch.vgic.nr_spis +
+			     VGIC_NR_PRIVATE_IRQS, uaddr);
+		break;
+	}
+	}
+
+	return r;
+}
+
 static int vgic_create(struct kvm_device *dev, u32 type)
 {
 	return kvm_vgic_create(dev->kvm, type);
@@ -49,18 +109,29 @@ void kvm_register_vgic_device(unsigned long type)
 static int vgic_v2_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	int ret;
+
+	ret = vgic_set_common_attr(dev, attr);
+	return ret;
+
 }
 
 static int vgic_v2_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	int ret;
+
+	ret = vgic_get_common_attr(dev, attr);
+	return ret;
 }
 
 static int vgic_v2_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		return 0;
+	}
 	return -ENXIO;
 }
 
@@ -80,18 +151,22 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
 static int vgic_v3_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	return vgic_set_common_attr(dev, attr);
 }
 
 static int vgic_v3_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	return vgic_get_common_attr(dev, attr);
 }
 
 static int vgic_v3_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		return 0;
+	}
 	return -ENXIO;
 }
 
-- 
2.7.3

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

* [RFC PATCH 31/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: kvmarm, kvm, linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_CTRL group API
featuring KVM_DEV_ARM_VGIC_CTRL_INIT attribute. The vgic_init
function is not yet implemented though.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_kvm_device.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index c96549b..18cccac 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -23,6 +23,8 @@
 static int vgic_set_common_attr(struct kvm_device *dev,
 				struct kvm_device_attr *attr)
 {
+	int r;
+
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
@@ -55,6 +57,16 @@ static int vgic_set_common_attr(struct kvm_device *dev,
 
 		return ret;
 	}
+	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			mutex_lock(&dev->kvm->lock);
+			r = vgic_init(dev->kvm);
+			mutex_unlock(&dev->kvm->lock);
+			return r;
+		}
+		break;
+	}
 	}
 
 	return -ENXIO;
@@ -131,6 +143,11 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return 0;
+		}
 	}
 	return -ENXIO;
 }
@@ -166,6 +183,11 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return 0;
+		}
 	}
 	return -ENXIO;
 }
-- 
2.7.3


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

* [RFC PATCH 31/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_CTRL group API
featuring KVM_DEV_ARM_VGIC_CTRL_INIT attribute. The vgic_init
function is not yet implemented though.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_kvm_device.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index c96549b..18cccac 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -23,6 +23,8 @@
 static int vgic_set_common_attr(struct kvm_device *dev,
 				struct kvm_device_attr *attr)
 {
+	int r;
+
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
@@ -55,6 +57,16 @@ static int vgic_set_common_attr(struct kvm_device *dev,
 
 		return ret;
 	}
+	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			mutex_lock(&dev->kvm->lock);
+			r = vgic_init(dev->kvm);
+			mutex_unlock(&dev->kvm->lock);
+			return r;
+		}
+		break;
+	}
 	}
 
 	return -ENXIO;
@@ -131,6 +143,11 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return 0;
+		}
 	}
 	return -ENXIO;
 }
@@ -166,6 +183,11 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return 0;
+		}
 	}
 	return -ENXIO;
 }
-- 
2.7.3

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

* [RFC PATCH 32/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_ADDR group which
enables to set the base address of GIC regions as seen by the guest.

The kvm_vgic_addr function whci eventually assigns the chosen address
to the internal structure still is stubbed.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_kvm_device.c | 38 +++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index 18cccac..d6fb2d6 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -26,6 +26,17 @@ static int vgic_set_common_attr(struct kvm_device *dev,
 	int r;
 
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 addr;
+		unsigned long type = (unsigned long)attr->attr;
+
+		if (copy_from_user(&addr, uaddr, sizeof(addr)))
+			return -EFAULT;
+
+		r = kvm_vgic_addr(dev->kvm, type, &addr, true);
+		return (r == -ENODEV) ? -ENXIO : r;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
 		u32 val;
@@ -78,6 +89,19 @@ static int vgic_get_common_attr(struct kvm_device *dev,
 	int r = -ENXIO;
 
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 addr;
+		unsigned long type = (unsigned long)attr->attr;
+
+		r = kvm_vgic_addr(dev->kvm, type, &addr, false);
+		if (r)
+			return (r == -ENODEV) ? -ENXIO : r;
+
+		if (copy_to_user(uaddr, &addr, sizeof(addr)))
+			return -EFAULT;
+		break;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
 
@@ -141,6 +165,13 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+		switch (attr->attr) {
+		case KVM_VGIC_V2_ADDR_TYPE_DIST:
+		case KVM_VGIC_V2_ADDR_TYPE_CPU:
+			return 0;
+		}
+		break;
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
@@ -181,6 +212,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+		switch (attr->attr) {
+		case KVM_VGIC_V3_ADDR_TYPE_DIST:
+		case KVM_VGIC_V3_ADDR_TYPE_REDIST:
+			return 0;
+		}
+		break;
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
-- 
2.7.3

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

* [RFC PATCH 32/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_ADDR group which
enables to set the base address of GIC regions as seen by the guest.

The kvm_vgic_addr function whci eventually assigns the chosen address
to the internal structure still is stubbed.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_kvm_device.c | 38 +++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index 18cccac..d6fb2d6 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -26,6 +26,17 @@ static int vgic_set_common_attr(struct kvm_device *dev,
 	int r;
 
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 addr;
+		unsigned long type = (unsigned long)attr->attr;
+
+		if (copy_from_user(&addr, uaddr, sizeof(addr)))
+			return -EFAULT;
+
+		r = kvm_vgic_addr(dev->kvm, type, &addr, true);
+		return (r == -ENODEV) ? -ENXIO : r;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
 		u32 val;
@@ -78,6 +89,19 @@ static int vgic_get_common_attr(struct kvm_device *dev,
 	int r = -ENXIO;
 
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 addr;
+		unsigned long type = (unsigned long)attr->attr;
+
+		r = kvm_vgic_addr(dev->kvm, type, &addr, false);
+		if (r)
+			return (r == -ENODEV) ? -ENXIO : r;
+
+		if (copy_to_user(uaddr, &addr, sizeof(addr)))
+			return -EFAULT;
+		break;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
 
@@ -141,6 +165,13 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+		switch (attr->attr) {
+		case KVM_VGIC_V2_ADDR_TYPE_DIST:
+		case KVM_VGIC_V2_ADDR_TYPE_CPU:
+			return 0;
+		}
+		break;
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
@@ -181,6 +212,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+		switch (attr->attr) {
+		case KVM_VGIC_V3_ADDR_TYPE_DIST:
+		case KVM_VGIC_V3_ADDR_TYPE_REDIST:
+			return 0;
+		}
+		break;
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
-- 
2.7.3

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

* [RFC PATCH 33/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
access VGIC registers.

At that stage the interfaces with the MMIO API are not implemented:
- vgic_attr_regs_access
- vgic_v2_has_attr_regs

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.h            |  1 +
 virt/kvm/arm/vgic/vgic_kvm_device.c | 53 +++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic_mmio.c       | 34 ++++++++++++++++++++++++
 3 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 072bec1..ff7ac9a 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -32,6 +32,7 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 			int offset, int len, void *val);
+int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index d6fb2d6..dfe40a0 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -140,6 +140,21 @@ void kvm_register_vgic_device(unsigned long type)
 	}
 }
 
+/** vgic_attr_regs_access: allows user space to read/write VGIC registers
+ *
+ * @dev: kvm device handle
+ * @attr: kvm device attribute
+ * @reg: address the value is read or written
+ * @is_write: write flag
+ *
+ */
+static int vgic_attr_regs_access(struct kvm_device *dev,
+				 struct kvm_device_attr *attr,
+				 u32 *reg, bool is_write)
+{
+	return -ENXIO;
+}
+
 /* V2 ops */
 
 static int vgic_v2_set_attr(struct kvm_device *dev,
@@ -148,8 +163,23 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
 	int ret;
 
 	ret = vgic_set_common_attr(dev, attr);
-	return ret;
+	if (ret != -ENXIO)
+		return ret;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u32 reg;
+
+		if (get_user(reg, uaddr))
+			return -EFAULT;
 
+		return vgic_attr_regs_access(dev, attr, &reg, true);
+	}
+	}
+
+	return -ENXIO;
 }
 
 static int vgic_v2_get_attr(struct kvm_device *dev,
@@ -158,7 +188,23 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
 	int ret;
 
 	ret = vgic_get_common_attr(dev, attr);
-	return ret;
+	if (ret != -ENXIO)
+		return ret;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u32 reg = 0;
+
+		ret = vgic_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		return put_user(reg, uaddr);
+	}
+	}
+
+	return -ENXIO;
 }
 
 static int vgic_v2_has_attr(struct kvm_device *dev,
@@ -172,6 +218,9 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 			return 0;
 		}
 		break;
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		return vgic_v2_has_attr_regs(dev, attr);
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 7eb6b93..7d5d630 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -1241,3 +1241,37 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
 	}
 }
 #endif
+
+int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+	struct vgic_register_region *regions;
+	gpa_t addr;
+	int nr_regions, i, len;
+
+	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		regions = vgic_v2_dist_registers;
+		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		return -ENXIO;		/* TODO: describe CPU i/f regs also */
+	default:
+		return -ENXIO;
+	}
+
+	for (i = 0; i < nr_regions; i++) {
+		if (regions[i].bits_per_irq)
+			len = (regions[i].bits_per_irq * nr_irqs) / 8;
+		else
+			len = regions[i].len;
+
+		if (regions[i].reg_offset <= addr &&
+		    regions[i].reg_offset + len > addr)
+			return 0;
+	}
+
+	return -ENXIO;
+}
-- 
2.7.3

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

* [RFC PATCH 33/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
access VGIC registers.

At that stage the interfaces with the MMIO API are not implemented:
- vgic_attr_regs_access
- vgic_v2_has_attr_regs

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.h            |  1 +
 virt/kvm/arm/vgic/vgic_kvm_device.c | 53 +++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic_mmio.c       | 34 ++++++++++++++++++++++++
 3 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 072bec1..ff7ac9a 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -32,6 +32,7 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 			int offset, int len, void *val);
+int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index d6fb2d6..dfe40a0 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -140,6 +140,21 @@ void kvm_register_vgic_device(unsigned long type)
 	}
 }
 
+/** vgic_attr_regs_access: allows user space to read/write VGIC registers
+ *
+ * @dev: kvm device handle
+ * @attr: kvm device attribute
+ * @reg: address the value is read or written
+ * @is_write: write flag
+ *
+ */
+static int vgic_attr_regs_access(struct kvm_device *dev,
+				 struct kvm_device_attr *attr,
+				 u32 *reg, bool is_write)
+{
+	return -ENXIO;
+}
+
 /* V2 ops */
 
 static int vgic_v2_set_attr(struct kvm_device *dev,
@@ -148,8 +163,23 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
 	int ret;
 
 	ret = vgic_set_common_attr(dev, attr);
-	return ret;
+	if (ret != -ENXIO)
+		return ret;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u32 reg;
+
+		if (get_user(reg, uaddr))
+			return -EFAULT;
 
+		return vgic_attr_regs_access(dev, attr, &reg, true);
+	}
+	}
+
+	return -ENXIO;
 }
 
 static int vgic_v2_get_attr(struct kvm_device *dev,
@@ -158,7 +188,23 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
 	int ret;
 
 	ret = vgic_get_common_attr(dev, attr);
-	return ret;
+	if (ret != -ENXIO)
+		return ret;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u32 reg = 0;
+
+		ret = vgic_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		return put_user(reg, uaddr);
+	}
+	}
+
+	return -ENXIO;
 }
 
 static int vgic_v2_has_attr(struct kvm_device *dev,
@@ -172,6 +218,9 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 			return 0;
 		}
 		break;
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		return vgic_v2_has_attr_regs(dev, attr);
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 7eb6b93..7d5d630 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -1241,3 +1241,37 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
 	}
 }
 #endif
+
+int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+	struct vgic_register_region *regions;
+	gpa_t addr;
+	int nr_regions, i, len;
+
+	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		regions = vgic_v2_dist_registers;
+		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		return -ENXIO;		/* TODO: describe CPU i/f regs also */
+	default:
+		return -ENXIO;
+	}
+
+	for (i = 0; i < nr_regions; i++) {
+		if (regions[i].bits_per_irq)
+			len = (regions[i].bits_per_irq * nr_irqs) / 8;
+		else
+			len = regions[i].len;
+
+		if (regions[i].reg_offset <= addr &&
+		    regions[i].reg_offset + len > addr)
+			return 0;
+	}
+
+	return -ENXIO;
+}
-- 
2.7.3

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

* [RFC PATCH 34/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

kvm_vgic_addr is used by the userspace to set the base address of
the following register regions, as seen by the guest:
- distributor(v2 and v3),
- re-distributors (v3),
- CPU interface (v2).

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h             |   2 +
 virt/kvm/arm/vgic/vgic.h            |   3 +
 virt/kvm/arm/vgic/vgic_kvm_device.c | 112 ++++++++++++++++++++++++++++++++++++
 3 files changed, 117 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index ab5fcc7..43b4537 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -187,6 +187,8 @@ struct vgic_cpu {
 	struct list_head ap_list_head;
 };
 
+int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
 
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index ff7ac9a..c8fd30c 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -19,6 +19,9 @@
 #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
 #define IMPLEMENTER_ARM		0x43b
 
+#define VGIC_ADDR_UNDEF		(-1)
+#define IS_VGIC_ADDR_UNDEF(_x)  ((_x) == VGIC_ADDR_UNDEF)
+
 #define INTERRUPT_ID_BITS_SPIS	10
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index dfe40a0..d9f2383 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -16,10 +16,122 @@
 #include <linux/kvm_host.h>
 #include <kvm/vgic/vgic.h>
 #include <linux/uaccess.h>
+#include <asm/kvm_mmu.h>
 #include "vgic.h"
 
 /* common helpers */
 
+static int vgic_ioaddr_overlap(struct kvm *kvm)
+{
+	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
+	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
+
+	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
+		return 0;
+	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
+	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
+		return -EBUSY;
+	return 0;
+}
+
+static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
+			      phys_addr_t addr, phys_addr_t size)
+{
+	int ret;
+
+	if (addr & ~KVM_PHYS_MASK)
+		return -E2BIG;
+
+	if (addr & (SZ_4K - 1))
+		return -EINVAL;
+
+	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
+		return -EEXIST;
+	if (addr + size < addr)
+		return -EINVAL;
+
+	*ioaddr = addr;
+	ret = vgic_ioaddr_overlap(kvm);
+	if (ret)
+		*ioaddr = VGIC_ADDR_UNDEF;
+
+	return ret;
+}
+
+/**
+ * kvm_vgic_addr - set or get vgic VM base addresses
+ * @kvm:   pointer to the vm struct
+ * @type:  the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX
+ * @addr:  pointer to address value
+ * @write: if true set the address in the VM address space, if false read the
+ *          address
+ *
+ * Set or get the vgic base addresses for the distributor and the virtual CPU
+ * interface in the VM physical address space.  These addresses are properties
+ * of the emulated core/SoC and therefore user space initially knows this
+ * information.
+ */
+int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
+{
+	int r = 0;
+	struct vgic_dist *vgic = &kvm->arch.vgic;
+	int type_needed;
+	phys_addr_t *addr_ptr, block_size;
+	phys_addr_t alignment;
+
+	mutex_lock(&kvm->lock);
+	switch (type) {
+	case KVM_VGIC_V2_ADDR_TYPE_DIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
+		addr_ptr = &vgic->vgic_dist_base;
+		block_size = KVM_VGIC_V2_DIST_SIZE;
+		alignment = SZ_4K;
+		break;
+	case KVM_VGIC_V2_ADDR_TYPE_CPU:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
+		addr_ptr = &vgic->vgic_cpu_base;
+		block_size = KVM_VGIC_V2_CPU_SIZE;
+		alignment = SZ_4K;
+		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case KVM_VGIC_V3_ADDR_TYPE_DIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
+		addr_ptr = &vgic->vgic_dist_base;
+		block_size = KVM_VGIC_V3_DIST_SIZE;
+		alignment = SZ_64K;
+		break;
+	case KVM_VGIC_V3_ADDR_TYPE_REDIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
+		addr_ptr = &vgic->vgic_redist_base;
+		block_size = KVM_VGIC_V3_REDIST_SIZE;
+		alignment = SZ_64K;
+		break;
+#endif
+	default:
+		r = -ENODEV;
+		goto out;
+	}
+
+	if (vgic->vgic_model != type_needed) {
+		r = -ENODEV;
+		goto out;
+	}
+
+	if (write) {
+		if (!IS_ALIGNED(*addr, alignment))
+			r = -EINVAL;
+		else
+			r = vgic_ioaddr_assign(kvm, addr_ptr,
+					       *addr, block_size);
+	} else {
+		*addr = *addr_ptr;
+	}
+
+out:
+	mutex_unlock(&kvm->lock);
+	return r;
+}
+
 static int vgic_set_common_attr(struct kvm_device *dev,
 				struct kvm_device_attr *attr)
 {
-- 
2.7.3

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

* [RFC PATCH 34/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

kvm_vgic_addr is used by the userspace to set the base address of
the following register regions, as seen by the guest:
- distributor(v2 and v3),
- re-distributors (v3),
- CPU interface (v2).

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h             |   2 +
 virt/kvm/arm/vgic/vgic.h            |   3 +
 virt/kvm/arm/vgic/vgic_kvm_device.c | 112 ++++++++++++++++++++++++++++++++++++
 3 files changed, 117 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index ab5fcc7..43b4537 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -187,6 +187,8 @@ struct vgic_cpu {
 	struct list_head ap_list_head;
 };
 
+int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
 
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index ff7ac9a..c8fd30c 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -19,6 +19,9 @@
 #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
 #define IMPLEMENTER_ARM		0x43b
 
+#define VGIC_ADDR_UNDEF		(-1)
+#define IS_VGIC_ADDR_UNDEF(_x)  ((_x) == VGIC_ADDR_UNDEF)
+
 #define INTERRUPT_ID_BITS_SPIS	10
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index dfe40a0..d9f2383 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -16,10 +16,122 @@
 #include <linux/kvm_host.h>
 #include <kvm/vgic/vgic.h>
 #include <linux/uaccess.h>
+#include <asm/kvm_mmu.h>
 #include "vgic.h"
 
 /* common helpers */
 
+static int vgic_ioaddr_overlap(struct kvm *kvm)
+{
+	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
+	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
+
+	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
+		return 0;
+	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
+	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
+		return -EBUSY;
+	return 0;
+}
+
+static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
+			      phys_addr_t addr, phys_addr_t size)
+{
+	int ret;
+
+	if (addr & ~KVM_PHYS_MASK)
+		return -E2BIG;
+
+	if (addr & (SZ_4K - 1))
+		return -EINVAL;
+
+	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
+		return -EEXIST;
+	if (addr + size < addr)
+		return -EINVAL;
+
+	*ioaddr = addr;
+	ret = vgic_ioaddr_overlap(kvm);
+	if (ret)
+		*ioaddr = VGIC_ADDR_UNDEF;
+
+	return ret;
+}
+
+/**
+ * kvm_vgic_addr - set or get vgic VM base addresses
+ * @kvm:   pointer to the vm struct
+ * @type:  the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX
+ * @addr:  pointer to address value
+ * @write: if true set the address in the VM address space, if false read the
+ *          address
+ *
+ * Set or get the vgic base addresses for the distributor and the virtual CPU
+ * interface in the VM physical address space.  These addresses are properties
+ * of the emulated core/SoC and therefore user space initially knows this
+ * information.
+ */
+int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
+{
+	int r = 0;
+	struct vgic_dist *vgic = &kvm->arch.vgic;
+	int type_needed;
+	phys_addr_t *addr_ptr, block_size;
+	phys_addr_t alignment;
+
+	mutex_lock(&kvm->lock);
+	switch (type) {
+	case KVM_VGIC_V2_ADDR_TYPE_DIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
+		addr_ptr = &vgic->vgic_dist_base;
+		block_size = KVM_VGIC_V2_DIST_SIZE;
+		alignment = SZ_4K;
+		break;
+	case KVM_VGIC_V2_ADDR_TYPE_CPU:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
+		addr_ptr = &vgic->vgic_cpu_base;
+		block_size = KVM_VGIC_V2_CPU_SIZE;
+		alignment = SZ_4K;
+		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case KVM_VGIC_V3_ADDR_TYPE_DIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
+		addr_ptr = &vgic->vgic_dist_base;
+		block_size = KVM_VGIC_V3_DIST_SIZE;
+		alignment = SZ_64K;
+		break;
+	case KVM_VGIC_V3_ADDR_TYPE_REDIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
+		addr_ptr = &vgic->vgic_redist_base;
+		block_size = KVM_VGIC_V3_REDIST_SIZE;
+		alignment = SZ_64K;
+		break;
+#endif
+	default:
+		r = -ENODEV;
+		goto out;
+	}
+
+	if (vgic->vgic_model != type_needed) {
+		r = -ENODEV;
+		goto out;
+	}
+
+	if (write) {
+		if (!IS_ALIGNED(*addr, alignment))
+			r = -EINVAL;
+		else
+			r = vgic_ioaddr_assign(kvm, addr_ptr,
+					       *addr, block_size);
+	} else {
+		*addr = *addr_ptr;
+	}
+
+out:
+	mutex_unlock(&kvm->lock);
+	return r;
+}
+
 static int vgic_set_common_attr(struct kvm_device *dev,
 				struct kvm_device_attr *attr)
 {
-- 
2.7.3

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

* [RFC PATCH 35/45] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_kvm_device.c | 50 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index d9f2383..2e2f8b6 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -264,7 +264,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 				 struct kvm_device_attr *attr,
 				 u32 *reg, bool is_write)
 {
-	return -ENXIO;
+	gpa_t addr;
+	int cpuid, ret, c;
+	struct kvm_vcpu *vcpu, *tmp_vcpu;
+
+	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
+		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;
+	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
+	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	mutex_lock(&dev->kvm->lock);
+
+	ret = vgic_init(dev->kvm);
+	if (ret)
+		goto out;
+
+	if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/*
+	 * Ensure that no other VCPU is running by checking the vcpu->cpu
+	 * field.  If no other VPCUs are running we can safely access the VGIC
+	 * state, because even if another VPU is run after this point, that
+	 * VCPU will not touch the vgic state, because it will block on
+	 * getting the vgic->lock in kvm_vgic_sync_hwstate().
+	 */
+	kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) {
+		if (unlikely(tmp_vcpu->cpu != -1)) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		ret = -EINVAL;
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		ret = vgic_v2_dist_access(vcpu, is_write, addr, 4, reg);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+out:
+	mutex_unlock(&dev->kvm->lock);
+	return ret;
 }
 
 /* V2 ops */
-- 
2.7.3

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

* [RFC PATCH 35/45] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_kvm_device.c | 50 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index d9f2383..2e2f8b6 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -264,7 +264,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 				 struct kvm_device_attr *attr,
 				 u32 *reg, bool is_write)
 {
-	return -ENXIO;
+	gpa_t addr;
+	int cpuid, ret, c;
+	struct kvm_vcpu *vcpu, *tmp_vcpu;
+
+	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
+		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;
+	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
+	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	mutex_lock(&dev->kvm->lock);
+
+	ret = vgic_init(dev->kvm);
+	if (ret)
+		goto out;
+
+	if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/*
+	 * Ensure that no other VCPU is running by checking the vcpu->cpu
+	 * field.  If no other VPCUs are running we can safely access the VGIC
+	 * state, because even if another VPU is run after this point, that
+	 * VCPU will not touch the vgic state, because it will block on
+	 * getting the vgic->lock in kvm_vgic_sync_hwstate().
+	 */
+	kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) {
+		if (unlikely(tmp_vcpu->cpu != -1)) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		ret = -EINVAL;
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		ret = vgic_v2_dist_access(vcpu, is_write, addr, 4, reg);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+out:
+	mutex_unlock(&dev->kvm->lock);
+	return ret;
 }
 
 /* V2 ops */
-- 
2.7.3

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

* [RFC PATCH 36/45] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:04   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h     |  7 +++++++
 virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c | 22 ++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c    | 16 ++++++++++++++++
 virt/kvm/arm/vgic/vgic.h    | 18 ++++++++++++++++++
 5 files changed, 92 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 43b4537..c4102a0 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -167,6 +167,13 @@ struct vgic_v3_cpu_if {
 #endif
 };
 
+struct vgic_vmcr {
+	u32	ctlr;
+	u32	abpr;
+	u32	bpr;
+	u32	pmr;
+};
+
 struct vgic_cpu {
 	/* CPU vif control registers for world switch */
 	union {
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 1cec423..fe6da47 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -180,6 +180,35 @@ out:
 	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
 }
 
+void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr;
+
+	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
+	vmcr |= (vmcrp->abpr << GICH_VMCR_ALIAS_BINPOINT_SHIFT) &
+		GICH_VMCR_ALIAS_BINPOINT_MASK;
+	vmcr |= (vmcrp->bpr << GICH_VMCR_BINPOINT_SHIFT) &
+		GICH_VMCR_BINPOINT_MASK;
+	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
+		GICH_VMCR_PRIMASK_MASK;
+
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
+}
+
+void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
+
+	vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >>
+			GICH_VMCR_CTRL_SHIFT;
+	vmcrp->abpr = (vmcr & GICH_VMCR_ALIAS_BINPOINT_MASK) >>
+			GICH_VMCR_ALIAS_BINPOINT_SHIFT;
+	vmcrp->bpr  = (vmcr & GICH_VMCR_BINPOINT_MASK) >>
+			GICH_VMCR_BINPOINT_SHIFT;
+	vmcrp->pmr  = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
+			GICH_VMCR_PRIMASK_SHIFT;
+}
+
 void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 71b4bad..04ef7f9 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -189,3 +189,25 @@ void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr)
 	irq->target_vcpu = vcpu;
 	spin_unlock(&irq->irq_lock);
 }
+
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr;
+
+	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
+	vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
+	vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
+	vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
+
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
+}
+
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
+
+	vmcrp->ctlr = (vmcr & ICH_VMCR_CTLR_MASK) >> ICH_VMCR_CTLR_SHIFT;
+	vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
+	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
+	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index d6c8c92..8c19379 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -401,6 +401,22 @@ static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
 		vgic_v3_set_underflow(vcpu);
 }
 
+void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_set_vmcr(vcpu, vmcr);
+	else
+		vgic_v3_set_vmcr(vcpu, vmcr);
+}
+
+void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_get_vmcr(vcpu, vmcr);
+	else
+		vgic_v3_get_vmcr(vcpu, vmcr);
+}
+
 static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index c8fd30c..c6d3ff6 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -36,6 +36,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 			int offset, int len, void *val);
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
+void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
@@ -47,6 +49,8 @@ int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 			int offset, int len, void *val);
 int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, int len, void *val);
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 #else
 static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
 					       u64 mpidr)
@@ -81,8 +85,22 @@ static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
 {
 	return -ENXIO;
 }
+
+static inline
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+}
+
+static inline
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+}
+
 #endif
 
+void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+
 void kvm_register_vgic_device(unsigned long type);
 
 #endif
-- 
2.7.3

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

* [RFC PATCH 36/45] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
@ 2016-03-25  2:04   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h     |  7 +++++++
 virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c | 22 ++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c    | 16 ++++++++++++++++
 virt/kvm/arm/vgic/vgic.h    | 18 ++++++++++++++++++
 5 files changed, 92 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 43b4537..c4102a0 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -167,6 +167,13 @@ struct vgic_v3_cpu_if {
 #endif
 };
 
+struct vgic_vmcr {
+	u32	ctlr;
+	u32	abpr;
+	u32	bpr;
+	u32	pmr;
+};
+
 struct vgic_cpu {
 	/* CPU vif control registers for world switch */
 	union {
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 1cec423..fe6da47 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -180,6 +180,35 @@ out:
 	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
 }
 
+void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr;
+
+	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
+	vmcr |= (vmcrp->abpr << GICH_VMCR_ALIAS_BINPOINT_SHIFT) &
+		GICH_VMCR_ALIAS_BINPOINT_MASK;
+	vmcr |= (vmcrp->bpr << GICH_VMCR_BINPOINT_SHIFT) &
+		GICH_VMCR_BINPOINT_MASK;
+	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
+		GICH_VMCR_PRIMASK_MASK;
+
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
+}
+
+void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
+
+	vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >>
+			GICH_VMCR_CTRL_SHIFT;
+	vmcrp->abpr = (vmcr & GICH_VMCR_ALIAS_BINPOINT_MASK) >>
+			GICH_VMCR_ALIAS_BINPOINT_SHIFT;
+	vmcrp->bpr  = (vmcr & GICH_VMCR_BINPOINT_MASK) >>
+			GICH_VMCR_BINPOINT_SHIFT;
+	vmcrp->pmr  = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
+			GICH_VMCR_PRIMASK_SHIFT;
+}
+
 void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 71b4bad..04ef7f9 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -189,3 +189,25 @@ void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr)
 	irq->target_vcpu = vcpu;
 	spin_unlock(&irq->irq_lock);
 }
+
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr;
+
+	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
+	vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
+	vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
+	vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
+
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
+}
+
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
+
+	vmcrp->ctlr = (vmcr & ICH_VMCR_CTLR_MASK) >> ICH_VMCR_CTLR_SHIFT;
+	vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
+	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
+	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index d6c8c92..8c19379 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -401,6 +401,22 @@ static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
 		vgic_v3_set_underflow(vcpu);
 }
 
+void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_set_vmcr(vcpu, vmcr);
+	else
+		vgic_v3_set_vmcr(vcpu, vmcr);
+}
+
+void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_get_vmcr(vcpu, vmcr);
+	else
+		vgic_v3_get_vmcr(vcpu, vmcr);
+}
+
 static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index c8fd30c..c6d3ff6 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -36,6 +36,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 			int offset, int len, void *val);
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
+void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
@@ -47,6 +49,8 @@ int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 			int offset, int len, void *val);
 int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, int len, void *val);
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 #else
 static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
 					       u64 mpidr)
@@ -81,8 +85,22 @@ static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
 {
 	return -ENXIO;
 }
+
+static inline
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+}
+
+static inline
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+}
+
 #endif
 
+void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+
 void kvm_register_vgic_device(unsigned long type);
 
 #endif
-- 
2.7.3

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

* [RFC PATCH 37/45] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:05   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_kvm_device.c | 72 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index 2e2f8b6..7f78a16 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -17,8 +17,11 @@
 #include <kvm/vgic/vgic.h>
 #include <linux/uaccess.h>
 #include <asm/kvm_mmu.h>
+#include <linux/irqchip/arm-gic.h>
 #include "vgic.h"
 
+#define GICC_ARCH_VERSION_V2		0x2
+
 /* common helpers */
 
 static int vgic_ioaddr_overlap(struct kvm *kvm)
@@ -252,6 +255,69 @@ void kvm_register_vgic_device(unsigned long type)
 	}
 }
 
+static u32 vgic_read_vcpuif(struct kvm_vcpu *vcpu, int offset)
+{
+	struct vgic_vmcr vmcr;
+	u32 *field;
+
+	switch (offset) {
+	case GIC_CPU_CTRL:
+		field = &vmcr.ctlr;
+		break;
+	case GIC_CPU_PRIMASK:
+		field = &vmcr.pmr;
+		break;
+	case GIC_CPU_BINPOINT:
+		field = &vmcr.bpr;
+		break;
+	case GIC_CPU_ALIAS_BINPOINT:
+		field = &vmcr.abpr;
+		break;
+	case GIC_CPU_IDENT:
+		return (PRODUCT_ID_KVM << 20) |
+		       (GICC_ARCH_VERSION_V2 << 16) |
+		       (IMPLEMENTER_ARM << 0);
+	default:
+		return 0;
+	}
+
+	vgic_get_vmcr(vcpu, &vmcr);
+
+	return *field;
+}
+
+static bool vgic_write_vcpuif(struct kvm_vcpu *vcpu, int offset, u32 value)
+{
+	struct vgic_vmcr vmcr;
+	u32 *field;
+
+	switch (offset) {
+	case GIC_CPU_CTRL:
+		field = &vmcr.ctlr;
+		break;
+	case GIC_CPU_PRIMASK:
+		field = &vmcr.pmr;
+		break;
+	case GIC_CPU_BINPOINT:
+		field = &vmcr.bpr;
+		break;
+	case GIC_CPU_ALIAS_BINPOINT:
+		field = &vmcr.abpr;
+		break;
+	default:
+		return false;
+	}
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (*field == value)
+		return false;
+
+	*field = value;
+	vgic_set_vmcr(vcpu, &vmcr);
+
+	return true;
+}
+
 /** vgic_attr_regs_access: allows user space to read/write VGIC registers
  *
  * @dev: kvm device handle
@@ -300,7 +366,11 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
-		ret = -EINVAL;
+		ret = 0;
+		if (is_write)
+			vgic_write_vcpuif(vcpu, addr, *reg);
+		else
+			*reg = vgic_read_vcpuif(vcpu, addr);
 		break;
 	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
 		ret = vgic_v2_dist_access(vcpu, is_write, addr, 4, reg);
-- 
2.7.3

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

* [RFC PATCH 37/45] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
@ 2016-03-25  2:05   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_kvm_device.c | 72 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index 2e2f8b6..7f78a16 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -17,8 +17,11 @@
 #include <kvm/vgic/vgic.h>
 #include <linux/uaccess.h>
 #include <asm/kvm_mmu.h>
+#include <linux/irqchip/arm-gic.h>
 #include "vgic.h"
 
+#define GICC_ARCH_VERSION_V2		0x2
+
 /* common helpers */
 
 static int vgic_ioaddr_overlap(struct kvm *kvm)
@@ -252,6 +255,69 @@ void kvm_register_vgic_device(unsigned long type)
 	}
 }
 
+static u32 vgic_read_vcpuif(struct kvm_vcpu *vcpu, int offset)
+{
+	struct vgic_vmcr vmcr;
+	u32 *field;
+
+	switch (offset) {
+	case GIC_CPU_CTRL:
+		field = &vmcr.ctlr;
+		break;
+	case GIC_CPU_PRIMASK:
+		field = &vmcr.pmr;
+		break;
+	case GIC_CPU_BINPOINT:
+		field = &vmcr.bpr;
+		break;
+	case GIC_CPU_ALIAS_BINPOINT:
+		field = &vmcr.abpr;
+		break;
+	case GIC_CPU_IDENT:
+		return (PRODUCT_ID_KVM << 20) |
+		       (GICC_ARCH_VERSION_V2 << 16) |
+		       (IMPLEMENTER_ARM << 0);
+	default:
+		return 0;
+	}
+
+	vgic_get_vmcr(vcpu, &vmcr);
+
+	return *field;
+}
+
+static bool vgic_write_vcpuif(struct kvm_vcpu *vcpu, int offset, u32 value)
+{
+	struct vgic_vmcr vmcr;
+	u32 *field;
+
+	switch (offset) {
+	case GIC_CPU_CTRL:
+		field = &vmcr.ctlr;
+		break;
+	case GIC_CPU_PRIMASK:
+		field = &vmcr.pmr;
+		break;
+	case GIC_CPU_BINPOINT:
+		field = &vmcr.bpr;
+		break;
+	case GIC_CPU_ALIAS_BINPOINT:
+		field = &vmcr.abpr;
+		break;
+	default:
+		return false;
+	}
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (*field == value)
+		return false;
+
+	*field = value;
+	vgic_set_vmcr(vcpu, &vmcr);
+
+	return true;
+}
+
 /** vgic_attr_regs_access: allows user space to read/write VGIC registers
  *
  * @dev: kvm device handle
@@ -300,7 +366,11 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
-		ret = -EINVAL;
+		ret = 0;
+		if (is_write)
+			vgic_write_vcpuif(vcpu, addr, *reg);
+		else
+			*reg = vgic_read_vcpuif(vcpu, addr);
 		break;
 	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
 		ret = vgic_v2_dist_access(vcpu, is_write, addr, 4, reg);
-- 
2.7.3

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

* [RFC PATCH 38/45] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:05   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

Implements kvm_vgic_hyp_init and vgic_probe function.

The vgic_global struct is enriched with new fields populated
by those functions.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |   1 +
 virt/kvm/arm/vgic/vgic-v2.c   |  90 +++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c   |  74 +++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h      |   6 +++
 virt/kvm/arm/vgic/vgic_init.c | 122 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 293 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic_init.c

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index c4102a0..1bc7b66 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -195,6 +195,7 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index fe6da47..0cb5c4f 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -17,6 +17,11 @@
 #include <linux/irqchip/arm-gic.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <kvm/vgic/vgic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/kvm_mmu.h>
 
 #include "vgic.h"
 
@@ -228,3 +233,88 @@ void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
 	irq->target_vcpu = kvm_get_vcpu(kvm, target);
 	spin_unlock(&irq->irq_lock);
 }
+
+/**
+ * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
+ * @node:	pointer to the DT node
+ *
+ * Returns 0 if a GICv2 has been found, returns an error code otherwise
+ */
+int vgic_v2_probe(struct device_node *vgic_node)
+{
+	int ret;
+	struct resource vctrl_res;
+	struct resource vcpu_res;
+
+	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
+	if (!kvm_vgic_global_state.maint_irq) {
+		kvm_err("error getting vgic maintenance irq from DT\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ret = of_address_to_resource(vgic_node, 2, &vctrl_res);
+	if (ret) {
+		kvm_err("Cannot obtain GICH resource\n");
+		goto out;
+	}
+
+	kvm_vgic_global_state.vctrl_base = of_iomap(vgic_node, 2);
+	if (!kvm_vgic_global_state.vctrl_base) {
+		kvm_err("Cannot ioremap GICH\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	kvm_vgic_global_state.nr_lr =
+		readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR);
+	kvm_vgic_global_state.nr_lr = (kvm_vgic_global_state.nr_lr & 0x3f) + 1;
+
+	ret = create_hyp_io_mappings(kvm_vgic_global_state.vctrl_base,
+				     kvm_vgic_global_state.vctrl_base +
+					 resource_size(&vctrl_res),
+				     vctrl_res.start);
+	if (ret) {
+		kvm_err("Cannot map VCTRL into hyp\n");
+		goto out_unmap;
+	}
+
+	if (of_address_to_resource(vgic_node, 3, &vcpu_res)) {
+		kvm_err("Cannot obtain GICV resource\n");
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	if (!PAGE_ALIGNED(vcpu_res.start)) {
+		kvm_err("GICV physical address 0x%llx not page aligned\n",
+			(unsigned long long)vcpu_res.start);
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
+		kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n",
+			(unsigned long long)resource_size(&vcpu_res),
+			PAGE_SIZE);
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	kvm_vgic_global_state.can_emulate_gicv2 = true;
+	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
+
+	kvm_vgic_global_state.vcpu_base = vcpu_res.start;
+
+	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
+		 vctrl_res.start, kvm_vgic_global_state.maint_irq);
+
+	kvm_vgic_global_state.type = VGIC_V2;
+	kvm_vgic_global_state.max_gic_vcpus = VGIC_V2_MAX_CPUS;
+	goto out;
+
+out_unmap:
+	iounmap(kvm_vgic_global_state.vctrl_base);
+out:
+	of_node_put(vgic_node);
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 04ef7f9..1a53141 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -16,9 +16,17 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/irqchip/arm-gic.h>
+#include <kvm/vgic/vgic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/kvm_mmu.h>
+#include <asm/kvm_asm.h>
 
 #include "vgic.h"
 
+static u32 ich_vtr_el2;
+
 void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -211,3 +219,69 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
+
+/**
+ * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
+ * @node:	pointer to the DT node
+ *
+ * Returns 0 if a GICv3 has been found, returns an error code otherwise
+ */
+int vgic_v3_probe(struct device_node *vgic_node)
+{
+	int ret = 0;
+	u32 gicv_idx;
+	struct resource vcpu_res;
+
+	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
+	if (!kvm_vgic_global_state.maint_irq) {
+		kvm_err("error getting vgic maintenance irq from DT\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);
+
+	/*
+	 * The ListRegs field is 5 bits, but there is a architectural
+	 * maximum of 16 list registers. Just ignore bit 4...
+	 */
+	kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
+	kvm_vgic_global_state.can_emulate_gicv2 = false;
+
+	if (of_property_read_u32(vgic_node, "#redistributor-regions",
+				 &gicv_idx))
+		gicv_idx = 1;
+
+	gicv_idx += 3; /* Also skip GICD, GICC, GICH */
+	if (of_address_to_resource(vgic_node, gicv_idx, &vcpu_res)) {
+		kvm_info("GICv3: no GICV resource entry\n");
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else if (!PAGE_ALIGNED(vcpu_res.start)) {
+		pr_warn("GICV physical address 0x%llx not page aligned\n",
+			(unsigned long long)vcpu_res.start);
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
+		pr_warn("GICV size 0x%llx not a multiple of page size 0x%lx\n",
+			(unsigned long long)resource_size(&vcpu_res),
+			PAGE_SIZE);
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else {
+		kvm_vgic_global_state.vcpu_base = vcpu_res.start;
+		kvm_vgic_global_state.can_emulate_gicv2 = true;
+		kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
+	}
+	if (kvm_vgic_global_state.vcpu_base == 0)
+		kvm_info("disabling GICv2 emulation\n");
+	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V3);
+
+	kvm_vgic_global_state.vctrl_base = NULL;
+	kvm_vgic_global_state.type = VGIC_V3;
+	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
+
+	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
+		 vcpu_res.start, kvm_vgic_global_state.maint_irq);
+
+out:
+	of_node_put(vgic_node);
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index c6d3ff6..31c9299a 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -38,6 +38,7 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+int vgic_v2_probe(struct device_node *vgic_node);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
@@ -51,6 +52,7 @@ int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, int len, void *val);
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+int vgic_v3_probe(struct device_node *vgic_node);
 #else
 static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
 					       u64 mpidr)
@@ -96,6 +98,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
 }
 
+static inline int vgic_v3_probe(struct device_node *vgic_node)
+{
+	return -ENODEV;
+}
 #endif
 
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
new file mode 100644
index 0000000..d7c50bb
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_init.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/cpu.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/kvm_host.h>
+#include <kvm/vgic/vgic.h>
+#include <asm/kvm_mmu.h>
+#include "vgic.h"
+
+/* GENERIC PROBE */
+
+static void vgic_init_maintenance_interrupt(void *info)
+{
+	enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0);
+}
+
+static int vgic_cpu_notify(struct notifier_block *self,
+			   unsigned long action, void *cpu)
+{
+	switch (action) {
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		vgic_init_maintenance_interrupt(NULL);
+		break;
+	case CPU_DYING:
+	case CPU_DYING_FROZEN:
+		disable_percpu_irq(kvm_vgic_global_state.maint_irq);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block vgic_cpu_nb = {
+	.notifier_call = vgic_cpu_notify,
+};
+
+static irqreturn_t vgic_maintenance_handler(int irq, void *data)
+{
+	/*
+	 * We cannot rely on the vgic maintenance interrupt to be
+	 * delivered synchronously. This means we can only use it to
+	 * exit the VM, and we perform the handling of EOIed
+	 * interrupts on the exit path (see vgic_process_maintenance).
+	 */
+	return IRQ_HANDLED;
+}
+
+static const struct of_device_id vgic_ids[] = {
+	{ .compatible = "arm,cortex-a15-gic",	.data = vgic_v2_probe, },
+	{ .compatible = "arm,cortex-a7-gic",	.data = vgic_v2_probe, },
+	{ .compatible = "arm,gic-400",		.data = vgic_v2_probe, },
+	{ .compatible = "arm,gic-v3",		.data = vgic_v3_probe, },
+	{},
+};
+
+/**
+ * kvm_vgic_hyp_init: populates the kvm_vgic_global_state variable
+ * according to the host GIC model. Accordingly calls either
+ * vgic_v2/v3_probe which registers the KVM_DEVICE that can be
+ * instantiated by a guest later on .
+ */
+int kvm_vgic_hyp_init(void)
+{
+	const struct of_device_id *matched_id;
+	const int (*vgic_probe)(struct device_node *);
+	struct device_node *vgic_node;
+	int ret;
+
+	vgic_node = of_find_matching_node_and_match(NULL,
+						    vgic_ids, &matched_id);
+	if (!vgic_node) {
+		kvm_err("error: no compatible GIC node found\n");
+		return -ENODEV;
+	}
+
+	vgic_probe = matched_id->data;
+	ret = vgic_probe(vgic_node);
+	if (ret)
+		return ret;
+
+	ret = request_percpu_irq(kvm_vgic_global_state.maint_irq,
+				 vgic_maintenance_handler,
+				 "vgic", kvm_get_running_vcpus());
+	if (ret) {
+		kvm_err("Cannot register interrupt %d\n",
+			kvm_vgic_global_state.maint_irq);
+		return ret;
+	}
+
+	ret = __register_cpu_notifier(&vgic_cpu_nb);
+	if (ret) {
+		kvm_err("Cannot register vgic CPU notifier\n");
+		goto out_free_irq;
+	}
+
+	on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
+
+	return 0;
+
+out_free_irq:
+	free_percpu_irq(kvm_vgic_global_state.maint_irq,
+			kvm_get_running_vcpus());
+	return ret;
+}
-- 
2.7.3

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

* [RFC PATCH 38/45] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
@ 2016-03-25  2:05   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

Implements kvm_vgic_hyp_init and vgic_probe function.

The vgic_global struct is enriched with new fields populated
by those functions.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |   1 +
 virt/kvm/arm/vgic/vgic-v2.c   |  90 +++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c   |  74 +++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h      |   6 +++
 virt/kvm/arm/vgic/vgic_init.c | 122 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 293 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic_init.c

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index c4102a0..1bc7b66 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -195,6 +195,7 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index fe6da47..0cb5c4f 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -17,6 +17,11 @@
 #include <linux/irqchip/arm-gic.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <kvm/vgic/vgic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/kvm_mmu.h>
 
 #include "vgic.h"
 
@@ -228,3 +233,88 @@ void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
 	irq->target_vcpu = kvm_get_vcpu(kvm, target);
 	spin_unlock(&irq->irq_lock);
 }
+
+/**
+ * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
+ * @node:	pointer to the DT node
+ *
+ * Returns 0 if a GICv2 has been found, returns an error code otherwise
+ */
+int vgic_v2_probe(struct device_node *vgic_node)
+{
+	int ret;
+	struct resource vctrl_res;
+	struct resource vcpu_res;
+
+	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
+	if (!kvm_vgic_global_state.maint_irq) {
+		kvm_err("error getting vgic maintenance irq from DT\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ret = of_address_to_resource(vgic_node, 2, &vctrl_res);
+	if (ret) {
+		kvm_err("Cannot obtain GICH resource\n");
+		goto out;
+	}
+
+	kvm_vgic_global_state.vctrl_base = of_iomap(vgic_node, 2);
+	if (!kvm_vgic_global_state.vctrl_base) {
+		kvm_err("Cannot ioremap GICH\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	kvm_vgic_global_state.nr_lr =
+		readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR);
+	kvm_vgic_global_state.nr_lr = (kvm_vgic_global_state.nr_lr & 0x3f) + 1;
+
+	ret = create_hyp_io_mappings(kvm_vgic_global_state.vctrl_base,
+				     kvm_vgic_global_state.vctrl_base +
+					 resource_size(&vctrl_res),
+				     vctrl_res.start);
+	if (ret) {
+		kvm_err("Cannot map VCTRL into hyp\n");
+		goto out_unmap;
+	}
+
+	if (of_address_to_resource(vgic_node, 3, &vcpu_res)) {
+		kvm_err("Cannot obtain GICV resource\n");
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	if (!PAGE_ALIGNED(vcpu_res.start)) {
+		kvm_err("GICV physical address 0x%llx not page aligned\n",
+			(unsigned long long)vcpu_res.start);
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
+		kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n",
+			(unsigned long long)resource_size(&vcpu_res),
+			PAGE_SIZE);
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	kvm_vgic_global_state.can_emulate_gicv2 = true;
+	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
+
+	kvm_vgic_global_state.vcpu_base = vcpu_res.start;
+
+	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
+		 vctrl_res.start, kvm_vgic_global_state.maint_irq);
+
+	kvm_vgic_global_state.type = VGIC_V2;
+	kvm_vgic_global_state.max_gic_vcpus = VGIC_V2_MAX_CPUS;
+	goto out;
+
+out_unmap:
+	iounmap(kvm_vgic_global_state.vctrl_base);
+out:
+	of_node_put(vgic_node);
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 04ef7f9..1a53141 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -16,9 +16,17 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/irqchip/arm-gic.h>
+#include <kvm/vgic/vgic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/kvm_mmu.h>
+#include <asm/kvm_asm.h>
 
 #include "vgic.h"
 
+static u32 ich_vtr_el2;
+
 void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -211,3 +219,69 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
+
+/**
+ * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
+ * @node:	pointer to the DT node
+ *
+ * Returns 0 if a GICv3 has been found, returns an error code otherwise
+ */
+int vgic_v3_probe(struct device_node *vgic_node)
+{
+	int ret = 0;
+	u32 gicv_idx;
+	struct resource vcpu_res;
+
+	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
+	if (!kvm_vgic_global_state.maint_irq) {
+		kvm_err("error getting vgic maintenance irq from DT\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);
+
+	/*
+	 * The ListRegs field is 5 bits, but there is a architectural
+	 * maximum of 16 list registers. Just ignore bit 4...
+	 */
+	kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
+	kvm_vgic_global_state.can_emulate_gicv2 = false;
+
+	if (of_property_read_u32(vgic_node, "#redistributor-regions",
+				 &gicv_idx))
+		gicv_idx = 1;
+
+	gicv_idx += 3; /* Also skip GICD, GICC, GICH */
+	if (of_address_to_resource(vgic_node, gicv_idx, &vcpu_res)) {
+		kvm_info("GICv3: no GICV resource entry\n");
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else if (!PAGE_ALIGNED(vcpu_res.start)) {
+		pr_warn("GICV physical address 0x%llx not page aligned\n",
+			(unsigned long long)vcpu_res.start);
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
+		pr_warn("GICV size 0x%llx not a multiple of page size 0x%lx\n",
+			(unsigned long long)resource_size(&vcpu_res),
+			PAGE_SIZE);
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else {
+		kvm_vgic_global_state.vcpu_base = vcpu_res.start;
+		kvm_vgic_global_state.can_emulate_gicv2 = true;
+		kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
+	}
+	if (kvm_vgic_global_state.vcpu_base == 0)
+		kvm_info("disabling GICv2 emulation\n");
+	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V3);
+
+	kvm_vgic_global_state.vctrl_base = NULL;
+	kvm_vgic_global_state.type = VGIC_V3;
+	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
+
+	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
+		 vcpu_res.start, kvm_vgic_global_state.maint_irq);
+
+out:
+	of_node_put(vgic_node);
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index c6d3ff6..31c9299a 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -38,6 +38,7 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+int vgic_v2_probe(struct device_node *vgic_node);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
@@ -51,6 +52,7 @@ int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, int len, void *val);
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+int vgic_v3_probe(struct device_node *vgic_node);
 #else
 static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
 					       u64 mpidr)
@@ -96,6 +98,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
 }
 
+static inline int vgic_v3_probe(struct device_node *vgic_node)
+{
+	return -ENODEV;
+}
 #endif
 
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
new file mode 100644
index 0000000..d7c50bb
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_init.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/cpu.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/kvm_host.h>
+#include <kvm/vgic/vgic.h>
+#include <asm/kvm_mmu.h>
+#include "vgic.h"
+
+/* GENERIC PROBE */
+
+static void vgic_init_maintenance_interrupt(void *info)
+{
+	enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0);
+}
+
+static int vgic_cpu_notify(struct notifier_block *self,
+			   unsigned long action, void *cpu)
+{
+	switch (action) {
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		vgic_init_maintenance_interrupt(NULL);
+		break;
+	case CPU_DYING:
+	case CPU_DYING_FROZEN:
+		disable_percpu_irq(kvm_vgic_global_state.maint_irq);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block vgic_cpu_nb = {
+	.notifier_call = vgic_cpu_notify,
+};
+
+static irqreturn_t vgic_maintenance_handler(int irq, void *data)
+{
+	/*
+	 * We cannot rely on the vgic maintenance interrupt to be
+	 * delivered synchronously. This means we can only use it to
+	 * exit the VM, and we perform the handling of EOIed
+	 * interrupts on the exit path (see vgic_process_maintenance).
+	 */
+	return IRQ_HANDLED;
+}
+
+static const struct of_device_id vgic_ids[] = {
+	{ .compatible = "arm,cortex-a15-gic",	.data = vgic_v2_probe, },
+	{ .compatible = "arm,cortex-a7-gic",	.data = vgic_v2_probe, },
+	{ .compatible = "arm,gic-400",		.data = vgic_v2_probe, },
+	{ .compatible = "arm,gic-v3",		.data = vgic_v3_probe, },
+	{},
+};
+
+/**
+ * kvm_vgic_hyp_init: populates the kvm_vgic_global_state variable
+ * according to the host GIC model. Accordingly calls either
+ * vgic_v2/v3_probe which registers the KVM_DEVICE that can be
+ * instantiated by a guest later on .
+ */
+int kvm_vgic_hyp_init(void)
+{
+	const struct of_device_id *matched_id;
+	const int (*vgic_probe)(struct device_node *);
+	struct device_node *vgic_node;
+	int ret;
+
+	vgic_node = of_find_matching_node_and_match(NULL,
+						    vgic_ids, &matched_id);
+	if (!vgic_node) {
+		kvm_err("error: no compatible GIC node found\n");
+		return -ENODEV;
+	}
+
+	vgic_probe = matched_id->data;
+	ret = vgic_probe(vgic_node);
+	if (ret)
+		return ret;
+
+	ret = request_percpu_irq(kvm_vgic_global_state.maint_irq,
+				 vgic_maintenance_handler,
+				 "vgic", kvm_get_running_vcpus());
+	if (ret) {
+		kvm_err("Cannot register interrupt %d\n",
+			kvm_vgic_global_state.maint_irq);
+		return ret;
+	}
+
+	ret = __register_cpu_notifier(&vgic_cpu_nb);
+	if (ret) {
+		kvm_err("Cannot register vgic CPU notifier\n");
+		goto out_free_irq;
+	}
+
+	on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
+
+	return 0;
+
+out_free_irq:
+	free_percpu_irq(kvm_vgic_global_state.maint_irq,
+			kvm_get_running_vcpus());
+	return ret;
+}
-- 
2.7.3

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

* [RFC PATCH 39/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:05   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch implements the vgic_creation function which is
called on CREATE_IRQCHIP VM IOCTL (v2 only) or KVM_CREATE_DEVICE

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |  1 +
 virt/kvm/arm/vgic/vgic_init.c | 84 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 1bc7b66..536582b 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -195,6 +195,7 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+int kvm_vgic_create(struct kvm *kvm, u32 type);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
index d7c50bb..80bf283 100644
--- a/virt/kvm/arm/vgic/vgic_init.c
+++ b/virt/kvm/arm/vgic/vgic_init.c
@@ -24,6 +24,90 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+/* CREATION */
+
+/**
+ * kvm_vgic_create: triggered by the instantiation of the VGIC device by
+ * user space, either through the legacy ARM specific VM IOCTL (CREATE_IRQCHIP)
+ * or through the generic VM IOCTL, KVM_CREATE_DEVICE API.
+ * Completion can be tested by irqchip_in_kernel
+ */
+int kvm_vgic_create(struct kvm *kvm, u32 type)
+{
+	int i, vcpu_lock_idx = -1, ret;
+	struct kvm_vcpu *vcpu;
+
+	mutex_lock(&kvm->lock);
+
+	if (irqchip_in_kernel(kvm)) {
+		ret = -EEXIST;
+		goto out;
+	}
+
+	/*
+	 * This function is also called by the KVM_CREATE_IRQCHIP handler,
+	 * which had no chance yet to check the availability of the GICv2
+	 * emulation. So check this here again. KVM_CREATE_DEVICE does
+	 * the proper checks already.
+	 */
+	if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
+		!kvm_vgic_global_state.can_emulate_gicv2) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/*
+	 * Any time a vcpu is run, vcpu_load is called which tries to grab the
+	 * vcpu->mutex.  By grabbing the vcpu->mutex of all VCPUs we ensure
+	 * that no other VCPUs are run while we create the vgic.
+	 */
+	ret = -EBUSY;
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (!mutex_trylock(&vcpu->mutex))
+			goto out_unlock;
+		vcpu_lock_idx = i;
+	}
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (vcpu->arch.has_run_once)
+			goto out_unlock;
+	}
+	ret = 0;
+
+	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
+		kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
+	else
+		kvm->arch.max_vcpus = VGIC_V3_MAX_CPUS;
+
+	if (atomic_read(&kvm->online_vcpus) > kvm->arch.max_vcpus) {
+		ret = -E2BIG;
+		goto out_unlock;
+	}
+
+	kvm->arch.vgic.in_kernel = true;
+	kvm->arch.vgic.vgic_model = type;
+
+	/*
+	 * kvm_vgic_global_state.vctrl_base is set on vgic probe (kvm_arch_init)
+	 * it is stored in distributor struct for asm save/restore purpose
+	 */
+	kvm->arch.vgic.vctrl_base = kvm_vgic_global_state.vctrl_base;
+
+	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
+	kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
+	kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
+
+out_unlock:
+	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
+		vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
+		mutex_unlock(&vcpu->mutex);
+	}
+
+out:
+	mutex_unlock(&kvm->lock);
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
-- 
2.7.3

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

* [RFC PATCH 39/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
@ 2016-03-25  2:05   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch implements the vgic_creation function which is
called on CREATE_IRQCHIP VM IOCTL (v2 only) or KVM_CREATE_DEVICE

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |  1 +
 virt/kvm/arm/vgic/vgic_init.c | 84 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 1bc7b66..536582b 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -195,6 +195,7 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+int kvm_vgic_create(struct kvm *kvm, u32 type);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
index d7c50bb..80bf283 100644
--- a/virt/kvm/arm/vgic/vgic_init.c
+++ b/virt/kvm/arm/vgic/vgic_init.c
@@ -24,6 +24,90 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+/* CREATION */
+
+/**
+ * kvm_vgic_create: triggered by the instantiation of the VGIC device by
+ * user space, either through the legacy ARM specific VM IOCTL (CREATE_IRQCHIP)
+ * or through the generic VM IOCTL, KVM_CREATE_DEVICE API.
+ * Completion can be tested by irqchip_in_kernel
+ */
+int kvm_vgic_create(struct kvm *kvm, u32 type)
+{
+	int i, vcpu_lock_idx = -1, ret;
+	struct kvm_vcpu *vcpu;
+
+	mutex_lock(&kvm->lock);
+
+	if (irqchip_in_kernel(kvm)) {
+		ret = -EEXIST;
+		goto out;
+	}
+
+	/*
+	 * This function is also called by the KVM_CREATE_IRQCHIP handler,
+	 * which had no chance yet to check the availability of the GICv2
+	 * emulation. So check this here again. KVM_CREATE_DEVICE does
+	 * the proper checks already.
+	 */
+	if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
+		!kvm_vgic_global_state.can_emulate_gicv2) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/*
+	 * Any time a vcpu is run, vcpu_load is called which tries to grab the
+	 * vcpu->mutex.  By grabbing the vcpu->mutex of all VCPUs we ensure
+	 * that no other VCPUs are run while we create the vgic.
+	 */
+	ret = -EBUSY;
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (!mutex_trylock(&vcpu->mutex))
+			goto out_unlock;
+		vcpu_lock_idx = i;
+	}
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (vcpu->arch.has_run_once)
+			goto out_unlock;
+	}
+	ret = 0;
+
+	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
+		kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
+	else
+		kvm->arch.max_vcpus = VGIC_V3_MAX_CPUS;
+
+	if (atomic_read(&kvm->online_vcpus) > kvm->arch.max_vcpus) {
+		ret = -E2BIG;
+		goto out_unlock;
+	}
+
+	kvm->arch.vgic.in_kernel = true;
+	kvm->arch.vgic.vgic_model = type;
+
+	/*
+	 * kvm_vgic_global_state.vctrl_base is set on vgic probe (kvm_arch_init)
+	 * it is stored in distributor struct for asm save/restore purpose
+	 */
+	kvm->arch.vgic.vctrl_base = kvm_vgic_global_state.vctrl_base;
+
+	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
+	kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
+	kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
+
+out_unlock:
+	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
+		vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
+		mutex_unlock(&vcpu->mutex);
+	}
+
+out:
+	mutex_unlock(&kvm->lock);
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
-- 
2.7.3

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

* [RFC PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:05   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch allocates and initializes the data structures used
to model the vgic distributor and virtual cpu interfaces. At that
stage the number of IRQs and number of virtual CPUs is frozen.

The following realy_init functions are kept since they are called from
arm.c. However they may disappear in subsequent patches since
they are void.

vgic_[v2|v3]_enable still is stubbed at this stage.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |   7 +-
 virt/kvm/arm/vgic/vgic-v2.c   |   5 +
 virt/kvm/arm/vgic/vgic-v3.c   |   5 +
 virt/kvm/arm/vgic/vgic.c      |   5 +
 virt/kvm/arm/vgic/vgic.h      |   8 ++
 virt/kvm/arm/vgic/vgic_init.c | 214 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 243 insertions(+), 1 deletion(-)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 536582b..4a51582 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -115,6 +115,7 @@ struct vgic_io_device {
 struct vgic_dist {
 	bool			in_kernel;
 	bool			ready;
+	bool			initialized;
 
 	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
 	u32			vgic_model;
@@ -195,7 +196,11 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+void kvm_vgic_early_init(struct kvm *kvm);
 int kvm_vgic_create(struct kvm *kvm, u32 type);
+void kvm_vgic_destroy(struct kvm *kvm);
+void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
+void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
@@ -204,7 +209,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
-#define vgic_initialized(k)	(false)
+#define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
 #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 0cb5c4f..c48dbd4 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -234,6 +234,11 @@ void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
 	spin_unlock(&irq->irq_lock);
 }
 
+/* not yet implemented */
+void vgic_v2_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 /**
  * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 1a53141..3155680 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -220,6 +220,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
 
+/* not yet implemented */
+void vgic_v3_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 8c19379..4ade7c0 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -268,6 +268,11 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level)
 {
 	struct kvm_vcpu *vcpu;
+	int ret;
+
+	ret = vgic_lazy_init(kvm);
+	if (ret)
+		return ret;
 
 	vcpu = kvm_get_vcpu(kvm, cpuid);
 	vgic_update_irq_pending(kvm, vcpu, intid, level);
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 31c9299a..4b2e1b0 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -38,6 +38,7 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v2_enable(struct kvm_vcpu *vcpu);
 int vgic_v2_probe(struct device_node *vgic_node);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
@@ -52,6 +53,7 @@ int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, int len, void *val);
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(struct device_node *vgic_node);
 #else
 static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
@@ -98,6 +100,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
 }
 
+static inline void vgic_v3_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 static inline int vgic_v3_probe(struct device_node *vgic_node)
 {
 	return -ENODEV;
@@ -107,6 +113,8 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 
+int vgic_lazy_init(struct kvm *kvm);
+int vgic_init(struct kvm *kvm);
 void kvm_register_vgic_device(unsigned long type);
 
 #endif
diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
index 80bf283..f7a6a11 100644
--- a/virt/kvm/arm/vgic/vgic_init.c
+++ b/virt/kvm/arm/vgic/vgic_init.c
@@ -24,6 +24,42 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+/*
+ * Initialization rules: there are multiple stages to the vgic
+ * initialization, both for the distributor and the CPU interfaces.
+ *
+ * Distributor:
+ *
+ * - kvm_vgic_early_init(): initialization of static data that doesn't
+ *   depend on any sizing information or emulation type. No allocation
+ *   is allowed there.
+ *
+ * - vgic_init(): allocation and initialization of the generic data
+ *   structures that depend on sizing information (number of CPUs,
+ *   number of interrupts). Also initializes the vcpu specific data
+ *   structures. Can be executed lazily for GICv2.
+ *
+ * CPU Interface:
+ *
+ * - kvm_vgic_cpu_early_init(): initialization of static data that
+ *   doesn't depend on any sizing information or emulation type. No
+ *   allocation is allowed there.
+ */
+
+/* EARLY INIT */
+
+/*
+ * Those 2 functions should not be needed anymore but they
+ * still are called from arm.c
+ */
+void kvm_vgic_early_init(struct kvm *kvm)
+{
+}
+
+void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
+{
+}
+
 /* CREATION */
 
 /**
@@ -108,6 +144,184 @@ out:
 	return ret;
 }
 
+/* INIT/DESTROY */
+
+/**
+ * kvm_vgic_dist_init: initialize the dist data structures
+ * @kvm: kvm struct pointer
+ * @nr_spis: number of spis, frozen by caller
+ */
+int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int i;
+
+	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
+	if (!dist->spis)
+		return  -ENOMEM;
+
+	/*
+	 * In following code we do not take the irq struct lock since
+	 * no other action on irq structs can happen while the VGIC is
+	 * not initialized yet:
+	 * injection requires (VGICV3) or does (VGIC2) initialization.
+	 * MMIO access triggers init.
+	 */
+	for (i = 0; i < nr_spis; i++) {
+		struct vgic_irq *irq = &dist->spis[i];
+
+		irq->intid = i + VGIC_NR_PRIVATE_IRQS;
+		INIT_LIST_HEAD(&irq->ap_list);
+		spin_lock_init(&irq->irq_lock);
+		irq->vcpu = NULL;
+		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
+			vgic_v2_irq_change_affinity(kvm, irq->intid, 0);
+		else
+			vgic_v3_irq_change_affinity(kvm, irq->intid, 0);
+	}
+	return 0;
+}
+
+/**
+ * kvm_vgic_vcpu_init: initialize the vcpu data structures and
+ * enable the VCPU interface
+ * @kvm: kvm struct pointer
+ */
+void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	int i;
+
+	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
+	spin_lock_init(&vgic_cpu->ap_list_lock);
+	vgic_cpu->nr_lr = kvm_vgic_global_state.nr_lr;
+
+	/*
+	 * Enable and configure all SGIs to be edge-triggered and
+	 * configure all PPIs as level-triggered.
+	 */
+	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
+		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
+
+		INIT_LIST_HEAD(&irq->ap_list);
+		spin_lock_init(&irq->irq_lock);
+		irq->intid = i;
+		irq->vcpu = NULL;
+		irq->target_vcpu = vcpu;
+		irq->targets = 1U << vcpu->vcpu_id;
+		if (i < VGIC_NR_SGIS) {
+			/* SGIs */
+			irq->enabled = 1;
+			irq->config = VGIC_CONFIG_EDGE;
+		} else {
+			/* PPIs */
+			irq->config = VGIC_CONFIG_LEVEL;
+		}
+	}
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_enable(vcpu);
+	else
+		vgic_v3_enable(vcpu);
+}
+
+/*
+ * vgic_init: allocates and initializes dist and vcpu data structures
+ * depending on two dimensioning parameters:
+ * - the number of spis
+ * - the number of vcpus
+ * The function is generally called when nr_spis has been explicitly set
+ * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
+ * Completion can be tested by vgic_initialized
+ * Must be called with kvm->lock held!
+ */
+int vgic_init(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct kvm_vcpu *vcpu;
+	int ret = 0, i;
+
+	if (vgic_initialized(kvm))
+		return 0;
+
+	/* freeze the number of spis */
+	if (!dist->nr_spis)
+		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
+
+	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
+	if (ret)
+		goto out;
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_vgic_vcpu_init(vcpu);
+
+	dist->initialized = true;
+out:
+	return ret;
+}
+
+static void kvm_vgic_dist_destroy(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	mutex_lock(&kvm->lock);
+
+	dist->ready = false;
+	dist->initialized = false;
+
+	kfree(dist->spis);
+	kfree(dist->dist_iodevs);
+	kfree(dist->redist_iodevs);
+	dist->nr_spis = 0;
+
+	mutex_unlock(&kvm->lock);
+}
+
+void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
+	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
+	vgic_cpu->nr_lr = 0;
+}
+
+void kvm_vgic_destroy(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	int i;
+
+	kvm_vgic_dist_destroy(kvm);
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_vgic_vcpu_destroy(vcpu);
+}
+
+/**
+ * Lazy init only is allowed if the GIC exposed to the guest is a GICV2.
+ * GICV3 must be explicitly initialized by the guest using the
+ * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group
+ */
+int vgic_lazy_init(struct kvm *kvm)
+{
+	int ret = 0;
+
+	if (unlikely(!vgic_initialized(kvm))) {
+		/*
+		 * We only provide the automatic initialization of the VGIC
+		 * for the legacy case of a GICv2. Any other type must
+		 * be explicitly initialized once setup with the respective
+		 * KVM device call.
+		 */
+		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
+			return -EBUSY;
+
+		mutex_lock(&kvm->lock);
+		ret = vgic_init(kvm);
+		mutex_unlock(&kvm->lock);
+	}
+
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
-- 
2.7.3

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

* [RFC PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
@ 2016-03-25  2:05   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch allocates and initializes the data structures used
to model the vgic distributor and virtual cpu interfaces. At that
stage the number of IRQs and number of virtual CPUs is frozen.

The following realy_init functions are kept since they are called from
arm.c. However they may disappear in subsequent patches since
they are void.

vgic_[v2|v3]_enable still is stubbed at this stage.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |   7 +-
 virt/kvm/arm/vgic/vgic-v2.c   |   5 +
 virt/kvm/arm/vgic/vgic-v3.c   |   5 +
 virt/kvm/arm/vgic/vgic.c      |   5 +
 virt/kvm/arm/vgic/vgic.h      |   8 ++
 virt/kvm/arm/vgic/vgic_init.c | 214 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 243 insertions(+), 1 deletion(-)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 536582b..4a51582 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -115,6 +115,7 @@ struct vgic_io_device {
 struct vgic_dist {
 	bool			in_kernel;
 	bool			ready;
+	bool			initialized;
 
 	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
 	u32			vgic_model;
@@ -195,7 +196,11 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+void kvm_vgic_early_init(struct kvm *kvm);
 int kvm_vgic_create(struct kvm *kvm, u32 type);
+void kvm_vgic_destroy(struct kvm *kvm);
+void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
+void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
@@ -204,7 +209,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
-#define vgic_initialized(k)	(false)
+#define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
 #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 0cb5c4f..c48dbd4 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -234,6 +234,11 @@ void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
 	spin_unlock(&irq->irq_lock);
 }
 
+/* not yet implemented */
+void vgic_v2_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 /**
  * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 1a53141..3155680 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -220,6 +220,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
 
+/* not yet implemented */
+void vgic_v3_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 8c19379..4ade7c0 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -268,6 +268,11 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level)
 {
 	struct kvm_vcpu *vcpu;
+	int ret;
+
+	ret = vgic_lazy_init(kvm);
+	if (ret)
+		return ret;
 
 	vcpu = kvm_get_vcpu(kvm, cpuid);
 	vgic_update_irq_pending(kvm, vcpu, intid, level);
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 31c9299a..4b2e1b0 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -38,6 +38,7 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v2_enable(struct kvm_vcpu *vcpu);
 int vgic_v2_probe(struct device_node *vgic_node);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
@@ -52,6 +53,7 @@ int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, int len, void *val);
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(struct device_node *vgic_node);
 #else
 static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
@@ -98,6 +100,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
 }
 
+static inline void vgic_v3_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 static inline int vgic_v3_probe(struct device_node *vgic_node)
 {
 	return -ENODEV;
@@ -107,6 +113,8 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 
+int vgic_lazy_init(struct kvm *kvm);
+int vgic_init(struct kvm *kvm);
 void kvm_register_vgic_device(unsigned long type);
 
 #endif
diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
index 80bf283..f7a6a11 100644
--- a/virt/kvm/arm/vgic/vgic_init.c
+++ b/virt/kvm/arm/vgic/vgic_init.c
@@ -24,6 +24,42 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+/*
+ * Initialization rules: there are multiple stages to the vgic
+ * initialization, both for the distributor and the CPU interfaces.
+ *
+ * Distributor:
+ *
+ * - kvm_vgic_early_init(): initialization of static data that doesn't
+ *   depend on any sizing information or emulation type. No allocation
+ *   is allowed there.
+ *
+ * - vgic_init(): allocation and initialization of the generic data
+ *   structures that depend on sizing information (number of CPUs,
+ *   number of interrupts). Also initializes the vcpu specific data
+ *   structures. Can be executed lazily for GICv2.
+ *
+ * CPU Interface:
+ *
+ * - kvm_vgic_cpu_early_init(): initialization of static data that
+ *   doesn't depend on any sizing information or emulation type. No
+ *   allocation is allowed there.
+ */
+
+/* EARLY INIT */
+
+/*
+ * Those 2 functions should not be needed anymore but they
+ * still are called from arm.c
+ */
+void kvm_vgic_early_init(struct kvm *kvm)
+{
+}
+
+void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
+{
+}
+
 /* CREATION */
 
 /**
@@ -108,6 +144,184 @@ out:
 	return ret;
 }
 
+/* INIT/DESTROY */
+
+/**
+ * kvm_vgic_dist_init: initialize the dist data structures
+ * @kvm: kvm struct pointer
+ * @nr_spis: number of spis, frozen by caller
+ */
+int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int i;
+
+	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
+	if (!dist->spis)
+		return  -ENOMEM;
+
+	/*
+	 * In following code we do not take the irq struct lock since
+	 * no other action on irq structs can happen while the VGIC is
+	 * not initialized yet:
+	 * injection requires (VGICV3) or does (VGIC2) initialization.
+	 * MMIO access triggers init.
+	 */
+	for (i = 0; i < nr_spis; i++) {
+		struct vgic_irq *irq = &dist->spis[i];
+
+		irq->intid = i + VGIC_NR_PRIVATE_IRQS;
+		INIT_LIST_HEAD(&irq->ap_list);
+		spin_lock_init(&irq->irq_lock);
+		irq->vcpu = NULL;
+		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
+			vgic_v2_irq_change_affinity(kvm, irq->intid, 0);
+		else
+			vgic_v3_irq_change_affinity(kvm, irq->intid, 0);
+	}
+	return 0;
+}
+
+/**
+ * kvm_vgic_vcpu_init: initialize the vcpu data structures and
+ * enable the VCPU interface
+ * @kvm: kvm struct pointer
+ */
+void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	int i;
+
+	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
+	spin_lock_init(&vgic_cpu->ap_list_lock);
+	vgic_cpu->nr_lr = kvm_vgic_global_state.nr_lr;
+
+	/*
+	 * Enable and configure all SGIs to be edge-triggered and
+	 * configure all PPIs as level-triggered.
+	 */
+	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
+		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
+
+		INIT_LIST_HEAD(&irq->ap_list);
+		spin_lock_init(&irq->irq_lock);
+		irq->intid = i;
+		irq->vcpu = NULL;
+		irq->target_vcpu = vcpu;
+		irq->targets = 1U << vcpu->vcpu_id;
+		if (i < VGIC_NR_SGIS) {
+			/* SGIs */
+			irq->enabled = 1;
+			irq->config = VGIC_CONFIG_EDGE;
+		} else {
+			/* PPIs */
+			irq->config = VGIC_CONFIG_LEVEL;
+		}
+	}
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_enable(vcpu);
+	else
+		vgic_v3_enable(vcpu);
+}
+
+/*
+ * vgic_init: allocates and initializes dist and vcpu data structures
+ * depending on two dimensioning parameters:
+ * - the number of spis
+ * - the number of vcpus
+ * The function is generally called when nr_spis has been explicitly set
+ * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
+ * Completion can be tested by vgic_initialized
+ * Must be called with kvm->lock held!
+ */
+int vgic_init(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct kvm_vcpu *vcpu;
+	int ret = 0, i;
+
+	if (vgic_initialized(kvm))
+		return 0;
+
+	/* freeze the number of spis */
+	if (!dist->nr_spis)
+		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
+
+	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
+	if (ret)
+		goto out;
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_vgic_vcpu_init(vcpu);
+
+	dist->initialized = true;
+out:
+	return ret;
+}
+
+static void kvm_vgic_dist_destroy(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	mutex_lock(&kvm->lock);
+
+	dist->ready = false;
+	dist->initialized = false;
+
+	kfree(dist->spis);
+	kfree(dist->dist_iodevs);
+	kfree(dist->redist_iodevs);
+	dist->nr_spis = 0;
+
+	mutex_unlock(&kvm->lock);
+}
+
+void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
+	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
+	vgic_cpu->nr_lr = 0;
+}
+
+void kvm_vgic_destroy(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	int i;
+
+	kvm_vgic_dist_destroy(kvm);
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_vgic_vcpu_destroy(vcpu);
+}
+
+/**
+ * Lazy init only is allowed if the GIC exposed to the guest is a GICV2.
+ * GICV3 must be explicitly initialized by the guest using the
+ * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group
+ */
+int vgic_lazy_init(struct kvm *kvm)
+{
+	int ret = 0;
+
+	if (unlikely(!vgic_initialized(kvm))) {
+		/*
+		 * We only provide the automatic initialization of the VGIC
+		 * for the legacy case of a GICv2. Any other type must
+		 * be explicitly initialized once setup with the respective
+		 * KVM device call.
+		 */
+		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
+			return -EBUSY;
+
+		mutex_lock(&kvm->lock);
+		ret = vgic_init(kvm);
+		mutex_unlock(&kvm->lock);
+	}
+
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
-- 
2.7.3

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

* [RFC PATCH 41/45] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:05   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

map_resources is the last initialization step. It is executed on
1st VCPU run. At that stage the code checks the userspace has provided
the base addresses for the relevant VGIC regions, which depend on
the type of VGIC that is exposed to the guest.

The function also forces the vgic_init if it has not been executed yet
(only allowed for VGIC v2).

for GICv2, The VGIC CPU interface is mapped onto the GIC virtual CPU
interface.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |  1 +
 virt/kvm/arm/vgic/vgic-v2.c   | 47 +++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c   | 44 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h      | 16 +++++++++++++++
 virt/kvm/arm/vgic/vgic_init.c | 27 +++++++++++++++++++++++++
 5 files changed, 135 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 4a51582..e418de9 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -201,6 +201,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type);
 void kvm_vgic_destroy(struct kvm *kvm);
 void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
 void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
+int kvm_vgic_map_resources(struct kvm *kvm);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index c48dbd4..8d0898c 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -239,6 +239,53 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
 {
 }
 
+int vgic_v2_map_resources(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int ret = 0;
+
+	if (vgic_ready(kvm))
+		goto out;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
+	    IS_VGIC_ADDR_UNDEF(dist->vgic_cpu_base)) {
+		kvm_err("Need to set vgic cpu and dist addresses first\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	/*
+	 * Initialize the vgic if this hasn't already been done on demand by
+	 * accessing the vgic state from userspace.
+	 */
+	ret = vgic_init(kvm);
+	if (ret) {
+		kvm_err("Unable to initialize VGIC dynamic data structures\n");
+		goto out;
+	}
+
+	ret = vgic_register_dist_regions(kvm, dist->vgic_dist_base, VGIC_V2);
+	if (ret) {
+		kvm_err("Unable to register VGIC MMIO regions\n");
+		goto out;
+	}
+
+	ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base,
+				    kvm_vgic_global_state.vcpu_base,
+				    KVM_VGIC_V2_CPU_SIZE, true);
+	if (ret) {
+		kvm_err("Unable to remap VGIC CPU to VCPU\n");
+		goto out;
+	}
+
+	dist->ready = true;
+
+out:
+	if (ret)
+		kvm_vgic_destroy(kvm);
+	return ret;
+}
+
 /**
  * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 3155680..705a269 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -225,6 +225,50 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 {
 }
 
+int vgic_v3_map_resources(struct kvm *kvm)
+{
+	int ret = 0;
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	if (vgic_ready(kvm))
+		goto out;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
+	    IS_VGIC_ADDR_UNDEF(dist->vgic_redist_base)) {
+		kvm_err("Need to set vgic distributor addresses first\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	/*
+	 * For a VGICv3 we require the userland to explicitly initialize
+	 * the VGIC before we need to use it.
+	 */
+	if (!vgic_initialized(kvm)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ret = vgic_register_dist_regions(kvm, dist->vgic_dist_base, VGIC_V3);
+	if (ret) {
+		kvm_err("Unable to register VGICv3 dist MMIO regions\n");
+		goto out;
+	}
+
+	ret = vgic_register_redist_regions(kvm, dist->vgic_redist_base);
+	if (ret) {
+		kvm_err("Unable to register VGICv3 redist MMIO regions\n");
+		goto out;
+	}
+
+	dist->ready = true;
+
+out:
+	if (ret)
+		kvm_vgic_destroy(kvm);
+	return ret;
+}
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 4b2e1b0..db9dfd7 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -40,6 +40,9 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_enable(struct kvm_vcpu *vcpu);
 int vgic_v2_probe(struct device_node *vgic_node);
+int vgic_v2_map_resources(struct kvm *kvm);
+int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
+			       enum vgic_type);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
@@ -55,6 +58,8 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(struct device_node *vgic_node);
+int vgic_v3_map_resources(struct kvm *kvm);
+int vgic_register_redist_regions(struct kvm *kvm, gpa_t dist_base_address);
 #else
 static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
 					       u64 mpidr)
@@ -108,6 +113,17 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
 {
 	return -ENODEV;
 }
+
+static inline int vgic_v3_map_resources(struct kvm *kvm)
+{
+	return -ENODEV;
+}
+
+static inline int vgic_register_redist_regions(struct kvm *kvm,
+					       gpa_t dist_base_address)
+{
+	return -ENODEV;
+}
 #endif
 
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
index f7a6a11..ac655b5 100644
--- a/virt/kvm/arm/vgic/vgic_init.c
+++ b/virt/kvm/arm/vgic/vgic_init.c
@@ -322,6 +322,33 @@ int vgic_lazy_init(struct kvm *kvm)
 	return ret;
 }
 
+/* RESOURCE MAPPING */
+
+/**
+ * Map the MMIO regions depending on the VGIC model exposed to the guest
+ * called on the first VCPU run.
+ * Also map the virtual CPU interface into the VM.
+ * v2/v3 derivatives call vgic_init if not already done.
+ * Completion can be tested by vgic_ready
+ */
+int kvm_vgic_map_resources(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int ret = 0;
+
+	mutex_lock(&kvm->lock);
+	if (!irqchip_in_kernel(kvm))
+		goto out;
+
+	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
+		ret = vgic_v2_map_resources(kvm);
+	else
+		ret = vgic_v3_map_resources(kvm);
+out:
+	mutex_unlock(&kvm->lock);
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
-- 
2.7.3

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

* [RFC PATCH 41/45] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
@ 2016-03-25  2:05   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

map_resources is the last initialization step. It is executed on
1st VCPU run. At that stage the code checks the userspace has provided
the base addresses for the relevant VGIC regions, which depend on
the type of VGIC that is exposed to the guest.

The function also forces the vgic_init if it has not been executed yet
(only allowed for VGIC v2).

for GICv2, The VGIC CPU interface is mapped onto the GIC virtual CPU
interface.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |  1 +
 virt/kvm/arm/vgic/vgic-v2.c   | 47 +++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c   | 44 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h      | 16 +++++++++++++++
 virt/kvm/arm/vgic/vgic_init.c | 27 +++++++++++++++++++++++++
 5 files changed, 135 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 4a51582..e418de9 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -201,6 +201,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type);
 void kvm_vgic_destroy(struct kvm *kvm);
 void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
 void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
+int kvm_vgic_map_resources(struct kvm *kvm);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index c48dbd4..8d0898c 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -239,6 +239,53 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
 {
 }
 
+int vgic_v2_map_resources(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int ret = 0;
+
+	if (vgic_ready(kvm))
+		goto out;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
+	    IS_VGIC_ADDR_UNDEF(dist->vgic_cpu_base)) {
+		kvm_err("Need to set vgic cpu and dist addresses first\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	/*
+	 * Initialize the vgic if this hasn't already been done on demand by
+	 * accessing the vgic state from userspace.
+	 */
+	ret = vgic_init(kvm);
+	if (ret) {
+		kvm_err("Unable to initialize VGIC dynamic data structures\n");
+		goto out;
+	}
+
+	ret = vgic_register_dist_regions(kvm, dist->vgic_dist_base, VGIC_V2);
+	if (ret) {
+		kvm_err("Unable to register VGIC MMIO regions\n");
+		goto out;
+	}
+
+	ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base,
+				    kvm_vgic_global_state.vcpu_base,
+				    KVM_VGIC_V2_CPU_SIZE, true);
+	if (ret) {
+		kvm_err("Unable to remap VGIC CPU to VCPU\n");
+		goto out;
+	}
+
+	dist->ready = true;
+
+out:
+	if (ret)
+		kvm_vgic_destroy(kvm);
+	return ret;
+}
+
 /**
  * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 3155680..705a269 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -225,6 +225,50 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 {
 }
 
+int vgic_v3_map_resources(struct kvm *kvm)
+{
+	int ret = 0;
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	if (vgic_ready(kvm))
+		goto out;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
+	    IS_VGIC_ADDR_UNDEF(dist->vgic_redist_base)) {
+		kvm_err("Need to set vgic distributor addresses first\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	/*
+	 * For a VGICv3 we require the userland to explicitly initialize
+	 * the VGIC before we need to use it.
+	 */
+	if (!vgic_initialized(kvm)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ret = vgic_register_dist_regions(kvm, dist->vgic_dist_base, VGIC_V3);
+	if (ret) {
+		kvm_err("Unable to register VGICv3 dist MMIO regions\n");
+		goto out;
+	}
+
+	ret = vgic_register_redist_regions(kvm, dist->vgic_redist_base);
+	if (ret) {
+		kvm_err("Unable to register VGICv3 redist MMIO regions\n");
+		goto out;
+	}
+
+	dist->ready = true;
+
+out:
+	if (ret)
+		kvm_vgic_destroy(kvm);
+	return ret;
+}
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 4b2e1b0..db9dfd7 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -40,6 +40,9 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_enable(struct kvm_vcpu *vcpu);
 int vgic_v2_probe(struct device_node *vgic_node);
+int vgic_v2_map_resources(struct kvm *kvm);
+int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
+			       enum vgic_type);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
@@ -55,6 +58,8 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(struct device_node *vgic_node);
+int vgic_v3_map_resources(struct kvm *kvm);
+int vgic_register_redist_regions(struct kvm *kvm, gpa_t dist_base_address);
 #else
 static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
 					       u64 mpidr)
@@ -108,6 +113,17 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
 {
 	return -ENODEV;
 }
+
+static inline int vgic_v3_map_resources(struct kvm *kvm)
+{
+	return -ENODEV;
+}
+
+static inline int vgic_register_redist_regions(struct kvm *kvm,
+					       gpa_t dist_base_address)
+{
+	return -ENODEV;
+}
 #endif
 
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
index f7a6a11..ac655b5 100644
--- a/virt/kvm/arm/vgic/vgic_init.c
+++ b/virt/kvm/arm/vgic/vgic_init.c
@@ -322,6 +322,33 @@ int vgic_lazy_init(struct kvm *kvm)
 	return ret;
 }
 
+/* RESOURCE MAPPING */
+
+/**
+ * Map the MMIO regions depending on the VGIC model exposed to the guest
+ * called on the first VCPU run.
+ * Also map the virtual CPU interface into the VM.
+ * v2/v3 derivatives call vgic_init if not already done.
+ * Completion can be tested by vgic_ready
+ */
+int kvm_vgic_map_resources(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int ret = 0;
+
+	mutex_lock(&kvm->lock);
+	if (!irqchip_in_kernel(kvm))
+		goto out;
+
+	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
+		ret = vgic_v2_map_resources(kvm);
+	else
+		ret = vgic_v3_map_resources(kvm);
+out:
+	mutex_unlock(&kvm->lock);
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
-- 
2.7.3

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

* [RFC PATCH 42/45] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:05   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

Enable the VGIC operation by properly initialising the registers
in the hypervisor GIC interface.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-v2.c | 11 ++++++++++-
 virt/kvm/arm/vgic/vgic-v3.c | 23 ++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 8d0898c..5f7c289 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -234,9 +234,18 @@ void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
 	spin_unlock(&irq->irq_lock);
 }
 
-/* not yet implemented */
 void vgic_v2_enable(struct kvm_vcpu *vcpu)
 {
+	/*
+	 * By forcing VMCR to zero, the GIC will restore the binary
+	 * points to their reset values. Anything else resets to zero
+	 * 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;
 }
 
 int vgic_v2_map_resources(struct kvm *kvm)
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 705a269..8944c46 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -220,9 +220,30 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
 
-/* not yet implemented */
 void vgic_v3_enable(struct kvm_vcpu *vcpu)
 {
+	struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	/*
+	 * By forcing VMCR to zero, the GIC will restore the binary
+	 * points to their reset values. Anything else resets to zero
+	 * 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
+	 * way, so we force SRE to 1 to demonstrate this to the guest.
+	 * This goes with the spec allowing the value to be RAO/WI.
+	 */
+	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
+		vgic_v3->vgic_sre = ICC_SRE_EL1_SRE;
+	else
+		vgic_v3->vgic_sre = 0;
+
+	/* Get the show on the road... */
+	vgic_v3->vgic_hcr = ICH_HCR_EN;
 }
 
 int vgic_v3_map_resources(struct kvm *kvm)
-- 
2.7.3

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

* [RFC PATCH 42/45] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
@ 2016-03-25  2:05   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

Enable the VGIC operation by properly initialising the registers
in the hypervisor GIC interface.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-v2.c | 11 ++++++++++-
 virt/kvm/arm/vgic/vgic-v3.c | 23 ++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 8d0898c..5f7c289 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -234,9 +234,18 @@ void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
 	spin_unlock(&irq->irq_lock);
 }
 
-/* not yet implemented */
 void vgic_v2_enable(struct kvm_vcpu *vcpu)
 {
+	/*
+	 * By forcing VMCR to zero, the GIC will restore the binary
+	 * points to their reset values. Anything else resets to zero
+	 * 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;
 }
 
 int vgic_v2_map_resources(struct kvm *kvm)
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 705a269..8944c46 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -220,9 +220,30 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
 
-/* not yet implemented */
 void vgic_v3_enable(struct kvm_vcpu *vcpu)
 {
+	struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	/*
+	 * By forcing VMCR to zero, the GIC will restore the binary
+	 * points to their reset values. Anything else resets to zero
+	 * 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
+	 * way, so we force SRE to 1 to demonstrate this to the guest.
+	 * This goes with the spec allowing the value to be RAO/WI.
+	 */
+	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
+		vgic_v3->vgic_sre = ICC_SRE_EL1_SRE;
+	else
+		vgic_v3->vgic_sre = 0;
+
+	/* Get the show on the road... */
+	vgic_v3->vgic_hcr = ICH_HCR_EN;
 }
 
 int vgic_v3_map_resources(struct kvm *kvm)
-- 
2.7.3

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

* [RFC PATCH 43/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:05   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

We now store the mapped hardware IRQ number in our struct, so we
don't need the irq_phys_map any longer for the new VGIC.
Implement the hardware IRQ mapping on top of the reworked arch
timer interface.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h  | 15 ++++++++
 virt/kvm/arm/vgic/vgic.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index e418de9..7c1d145 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -206,6 +206,21 @@ int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
+int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			       bool level);
+
+/*
+ * This is not really needed, but we need this type to keep the arch
+ * timer compatible with the old VGIC implementation.
+ * This should be removed upon retiring the old VGIC.
+ */
+struct irq_phys_map {};
+
+struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
+					   u32 virt_irq, u32 irq);
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
+			    u32 intid);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid);
 
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 4ade7c0..65395af 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -17,6 +17,9 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/list_sort.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdesc.h>
 
 #include "vgic.h"
 
@@ -276,6 +279,83 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 
 	vcpu = kvm_get_vcpu(kvm, cpuid);
 	vgic_update_irq_pending(kvm, vcpu, intid, level);
+
+	return 0;
+}
+
+/**
+ * kvm_vgic_inject_mapped_irq - Inject a hardware mapped IRQ to the vgic
+ * @kvm:     The VM structure pointer
+ * @cpuid:   The CPU for PPIs
+ * @irq_num: The INTID to inject a new state to.
+ * @level:   Edge-triggered:  true:  to trigger the interrupt
+ *			      false: to ignore the call
+ *	     Level-sensitive  true:  raise the input signal
+ *			      false: lower the input signal
+ *
+ * The GIC is not concerned with devices being active-LOW or active-HIGH for
+ * level-sensitive interrupts.  You can think of the level parameter as 1
+ * being HIGH and 0 being LOW and all devices being active-HIGH.
+ */
+int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			       bool level)
+{
+	struct kvm_vcpu *vcpu;
+	int ret;
+
+	ret = vgic_lazy_init(kvm);
+	if (ret)
+		return ret;
+
+	vcpu = kvm_get_vcpu(kvm, cpuid);
+	vgic_update_irq_pending(kvm, vcpu, intid, level);
+
+	return 0;
+}
+
+struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
+					   u32 virt_irq, u32 intid)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+	struct irq_desc *desc;
+	struct irq_data *data;
+
+	BUG_ON(!irq);
+
+	desc = irq_to_desc(intid);
+	if (!desc) {
+		kvm_err("%s: no interrupt descriptor\n", __func__);
+		return NULL;
+	}
+
+	data = irq_desc_get_irq_data(desc);
+	while (data->parent_data)
+		data = data->parent_data;
+
+	spin_lock(&irq->irq_lock);
+
+	irq->hw = true;
+	irq->hwintid = data->hwirq;
+
+	spin_unlock(&irq->irq_lock);
+
+	return NULL;
+}
+
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
+			    u32 intid)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+	BUG_ON(!irq);
+
+	spin_lock(&irq->irq_lock);
+
+	irq->hw = false;
+	irq->hwintid = 0;
+
+	spin_unlock(&irq->irq_lock);
+
 	return 0;
 }
 
@@ -520,3 +600,15 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
 
 	return pending;
 }
+
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+	bool map_is_active;
+
+	spin_lock(&irq->irq_lock);
+	map_is_active = irq->hw && irq->active;
+	spin_unlock(&irq->irq_lock);
+
+	return map_is_active;
+}
-- 
2.7.3

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

* [RFC PATCH 43/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
@ 2016-03-25  2:05   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: linux-arm-kernel

We now store the mapped hardware IRQ number in our struct, so we
don't need the irq_phys_map any longer for the new VGIC.
Implement the hardware IRQ mapping on top of the reworked arch
timer interface.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h  | 15 ++++++++
 virt/kvm/arm/vgic/vgic.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index e418de9..7c1d145 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -206,6 +206,21 @@ int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
+int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			       bool level);
+
+/*
+ * This is not really needed, but we need this type to keep the arch
+ * timer compatible with the old VGIC implementation.
+ * This should be removed upon retiring the old VGIC.
+ */
+struct irq_phys_map {};
+
+struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
+					   u32 virt_irq, u32 irq);
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
+			    u32 intid);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid);
 
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 4ade7c0..65395af 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -17,6 +17,9 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/list_sort.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdesc.h>
 
 #include "vgic.h"
 
@@ -276,6 +279,83 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 
 	vcpu = kvm_get_vcpu(kvm, cpuid);
 	vgic_update_irq_pending(kvm, vcpu, intid, level);
+
+	return 0;
+}
+
+/**
+ * kvm_vgic_inject_mapped_irq - Inject a hardware mapped IRQ to the vgic
+ * @kvm:     The VM structure pointer
+ * @cpuid:   The CPU for PPIs
+ * @irq_num: The INTID to inject a new state to.
+ * @level:   Edge-triggered:  true:  to trigger the interrupt
+ *			      false: to ignore the call
+ *	     Level-sensitive  true:  raise the input signal
+ *			      false: lower the input signal
+ *
+ * The GIC is not concerned with devices being active-LOW or active-HIGH for
+ * level-sensitive interrupts.  You can think of the level parameter as 1
+ * being HIGH and 0 being LOW and all devices being active-HIGH.
+ */
+int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			       bool level)
+{
+	struct kvm_vcpu *vcpu;
+	int ret;
+
+	ret = vgic_lazy_init(kvm);
+	if (ret)
+		return ret;
+
+	vcpu = kvm_get_vcpu(kvm, cpuid);
+	vgic_update_irq_pending(kvm, vcpu, intid, level);
+
+	return 0;
+}
+
+struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
+					   u32 virt_irq, u32 intid)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+	struct irq_desc *desc;
+	struct irq_data *data;
+
+	BUG_ON(!irq);
+
+	desc = irq_to_desc(intid);
+	if (!desc) {
+		kvm_err("%s: no interrupt descriptor\n", __func__);
+		return NULL;
+	}
+
+	data = irq_desc_get_irq_data(desc);
+	while (data->parent_data)
+		data = data->parent_data;
+
+	spin_lock(&irq->irq_lock);
+
+	irq->hw = true;
+	irq->hwintid = data->hwirq;
+
+	spin_unlock(&irq->irq_lock);
+
+	return NULL;
+}
+
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
+			    u32 intid)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+	BUG_ON(!irq);
+
+	spin_lock(&irq->irq_lock);
+
+	irq->hw = false;
+	irq->hwintid = 0;
+
+	spin_unlock(&irq->irq_lock);
+
 	return 0;
 }
 
@@ -520,3 +600,15 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
 
 	return pending;
 }
+
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+	bool map_is_active;
+
+	spin_lock(&irq->irq_lock);
+	map_is_active = irq->hw && irq->active;
+	spin_unlock(&irq->irq_lock);
+
+	return map_is_active;
+}
-- 
2.7.3

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

* [RFC PATCH 44/45] KVM: arm/arm64: vgic-new: Add dummy MSI implementation
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:05   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Although we don't provide any virtual MSI functionality yet, we
need to implement the functions required by the KVM interface.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_irqfd.c | 51 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c

diff --git a/virt/kvm/arm/vgic/vgic_irqfd.c b/virt/kvm/arm/vgic/vgic_irqfd.c
new file mode 100644
index 0000000..3eee1bd
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_irqfd.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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/kvm.h>
+#include <linux/kvm_host.h>
+#include <trace/events/kvm.h>
+
+int kvm_irq_map_gsi(struct kvm *kvm,
+		    struct kvm_kernel_irq_routing_entry *entries,
+		    int gsi)
+{
+	return 0;
+}
+
+int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
+{
+	return pin;
+}
+
+int kvm_set_irq(struct kvm *kvm, int irq_source_id,
+		u32 irq, int level, bool line_status)
+{
+	unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
+
+	trace_kvm_set_irq(irq, level, irq_source_id);
+
+	BUG_ON(!vgic_initialized(kvm));
+
+	return kvm_vgic_inject_irq(kvm, 0, spi, level);
+}
+
+/* MSI not implemented yet */
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+		struct kvm *kvm, int irq_source_id,
+		int level, bool line_status)
+{
+	return 0;
+}
-- 
2.7.3

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

* [RFC PATCH 44/45] KVM: arm/arm64: vgic-new: Add dummy MSI implementation
@ 2016-03-25  2:05   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: linux-arm-kernel

Although we don't provide any virtual MSI functionality yet, we
need to implement the functions required by the KVM interface.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic_irqfd.c | 51 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c

diff --git a/virt/kvm/arm/vgic/vgic_irqfd.c b/virt/kvm/arm/vgic/vgic_irqfd.c
new file mode 100644
index 0000000..3eee1bd
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_irqfd.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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/kvm.h>
+#include <linux/kvm_host.h>
+#include <trace/events/kvm.h>
+
+int kvm_irq_map_gsi(struct kvm *kvm,
+		    struct kvm_kernel_irq_routing_entry *entries,
+		    int gsi)
+{
+	return 0;
+}
+
+int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
+{
+	return pin;
+}
+
+int kvm_set_irq(struct kvm *kvm, int irq_source_id,
+		u32 irq, int level, bool line_status)
+{
+	unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
+
+	trace_kvm_set_irq(irq, level, irq_source_id);
+
+	BUG_ON(!vgic_initialized(kvm));
+
+	return kvm_vgic_inject_irq(kvm, 0, spi, level);
+}
+
+/* MSI not implemented yet */
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+		struct kvm *kvm, int irq_source_id,
+		int level, bool line_status)
+{
+	return 0;
+}
-- 
2.7.3

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

* [RFC PATCH 45/45] KVM: arm/arm64: vgic-new: enable build
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25  2:05   ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier, Eric Auger; +Cc: linux-arm-kernel, kvmarm, kvm

Now that the new VGIC implementation has reached feature parity with
the old one, add the new files to the build system and add a Kconfig
option to switch between the two versions.
We set the default to the new version to get maximum test coverage,
in case people experience problems they can switch back to the old
behaviour if needed.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/kvm/Kconfig    |  7 +++++++
 arch/arm/kvm/Makefile   | 10 ++++++++++
 arch/arm64/kvm/Kconfig  |  7 +++++++
 arch/arm64/kvm/Makefile | 10 ++++++++++
 4 files changed, 34 insertions(+)

diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
index 95a0005..02abfff 100644
--- a/arch/arm/kvm/Kconfig
+++ b/arch/arm/kvm/Kconfig
@@ -46,6 +46,13 @@ config KVM_ARM_HOST
 	---help---
 	  Provides host support for ARM processors.
 
+config KVM_NEW_VGIC
+	bool "New VGIC implementation"
+	depends on KVM
+	default y
+	---help---
+	  uses the new VGIC implementation
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index eb1bf43..aa7d724 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -21,7 +21,17 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp/
 obj-y += kvm-arm.o init.o interrupts.o
 obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
 obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
+
+ifeq ($(CONFIG_KVM_NEW_VGIC),y)
+obj-y += $(KVM)/arm/vgic/vgic.o
+obj-y += $(KVM)/arm/vgic/vgic_init.o
+obj-y += $(KVM)/arm/vgic/vgic_irqfd.o
+obj-y += $(KVM)/arm/vgic/vgic-v2.o
+obj-y += $(KVM)/arm/vgic/vgic_mmio.o
+obj-y += $(KVM)/arm/vgic/vgic_kvm_device.o
+else
 obj-y += $(KVM)/arm/vgic.o
 obj-y += $(KVM)/arm/vgic-v2.o
 obj-y += $(KVM)/arm/vgic-v2-emul.o
+endif
 obj-y += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index de7450d..3f0e1ce 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -55,6 +55,13 @@ config KVM_ARM_PMU
 	  Adds support for a virtual Performance Monitoring Unit (PMU) in
 	  virtual machines.
 
+config KVM_NEW_VGIC
+	bool "New VGIC implementation"
+	depends on KVM
+	default y
+        ---help---
+          uses the new VGIC implementation
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 122cff4..2f5d431 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -20,10 +20,20 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
 kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
 kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
 
+ifeq ($(CONFIG_KVM_NEW_VGIC),y)
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_init.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_irqfd.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_mmio.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_kvm_device.o
+else
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
+endif
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
 kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
-- 
2.7.3

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

* [RFC PATCH 45/45] KVM: arm/arm64: vgic-new: enable build
@ 2016-03-25  2:05   ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-03-25  2:05 UTC (permalink / raw)
  To: linux-arm-kernel

Now that the new VGIC implementation has reached feature parity with
the old one, add the new files to the build system and add a Kconfig
option to switch between the two versions.
We set the default to the new version to get maximum test coverage,
in case people experience problems they can switch back to the old
behaviour if needed.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/kvm/Kconfig    |  7 +++++++
 arch/arm/kvm/Makefile   | 10 ++++++++++
 arch/arm64/kvm/Kconfig  |  7 +++++++
 arch/arm64/kvm/Makefile | 10 ++++++++++
 4 files changed, 34 insertions(+)

diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
index 95a0005..02abfff 100644
--- a/arch/arm/kvm/Kconfig
+++ b/arch/arm/kvm/Kconfig
@@ -46,6 +46,13 @@ config KVM_ARM_HOST
 	---help---
 	  Provides host support for ARM processors.
 
+config KVM_NEW_VGIC
+	bool "New VGIC implementation"
+	depends on KVM
+	default y
+	---help---
+	  uses the new VGIC implementation
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index eb1bf43..aa7d724 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -21,7 +21,17 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp/
 obj-y += kvm-arm.o init.o interrupts.o
 obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
 obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
+
+ifeq ($(CONFIG_KVM_NEW_VGIC),y)
+obj-y += $(KVM)/arm/vgic/vgic.o
+obj-y += $(KVM)/arm/vgic/vgic_init.o
+obj-y += $(KVM)/arm/vgic/vgic_irqfd.o
+obj-y += $(KVM)/arm/vgic/vgic-v2.o
+obj-y += $(KVM)/arm/vgic/vgic_mmio.o
+obj-y += $(KVM)/arm/vgic/vgic_kvm_device.o
+else
 obj-y += $(KVM)/arm/vgic.o
 obj-y += $(KVM)/arm/vgic-v2.o
 obj-y += $(KVM)/arm/vgic-v2-emul.o
+endif
 obj-y += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index de7450d..3f0e1ce 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -55,6 +55,13 @@ config KVM_ARM_PMU
 	  Adds support for a virtual Performance Monitoring Unit (PMU) in
 	  virtual machines.
 
+config KVM_NEW_VGIC
+	bool "New VGIC implementation"
+	depends on KVM
+	default y
+        ---help---
+          uses the new VGIC implementation
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 122cff4..2f5d431 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -20,10 +20,20 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
 kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
 kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
 
+ifeq ($(CONFIG_KVM_NEW_VGIC),y)
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_init.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_irqfd.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_mmio.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_kvm_device.o
+else
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
+endif
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
 kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
-- 
2.7.3

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-25 15:58   ` Diana Madalina Craciun
  -1 siblings, 0 replies; 276+ messages in thread
From: Diana Madalina Craciun @ 2016-03-25 15:58 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall, Marc Zyngier, Eric Auger
  Cc: kvmarm, linux-arm-kernel, kvm

Hi Andre,

On which kernel version should I apply these series ?

Thanks,

Diana

On 03/25/2016 04:05 AM, Andre Przywara wrote:
> This series is a joint effort to re-implement KVM's GIC emulation.
>
> While the current implementation is centered around providing
> efficient MMIO emulation, the hot path for most guests is actually
> the guest entry and exit, which currently is rather costly.
> Also the existing emulation has a global distributor lock, which
> quickly becomes a bottleneck once the number of VCPUs increases.
> Additionally the emulation was originally designed for GICv2, adding
> GICv3 ITS emulation support to this proved to be rather painful.
> Last, but not least the existing code became less and less
> maintainable, with many special cases handled explicitly.
>
> The new implementation is build around a struct vgic_irq data data
> structure, which holds all information about a virtual interrupt.
> Interruts which should be injected are hold in a per-VCPU list, this
> make the entry/exit path much more efficient. Also the new structure
> allows to have more fine grained locking - per IRQ and per VCPU -
> getting rid of the global distributor lock.
> As a result of the new design ITS emulation fits in more nicely, the
> respective code will be provided as a follow-up series.
>
> This series implements the same feature set as the existing emulation,
> as a goodie we now implement priorities correctly.
> To allow an easy transition with good test coverage, but still maintain
> stability, both implementations live side by side, selectable via a
> Kconfig option. The default is the new implementation.
> If this code proves to be reliable, we will later remove the current
> implementation with an extra patch set.
>
> Please have a look at the series, review it and give the code some
> serious testing (and possibly debugging). All feedback is appreciated.
>
> Cheers,
> Andre.
>
> Andre Przywara (26):
>   KVM: arm/arm64: add missing MMIO data write-back
>   KVM: arm/arm64: pmu: abstract access to number of SPIs
>   KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface
>   KVM: arm/arm64: vgic-new: Add MMIO handling framework
>   KVM: arm/arm64: vgic-new: Export register access interface
>   KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
>   KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
>   KVM: arm/arm64: vgic-new: Add PENDING registers handlers
>   KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
>   KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
>   KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
>   KVM: arm/arm64: vgic-new: Add TARGET registers handlers
>   KVM: arm/arm64: vgic-new: Add SGIR register handler
>   KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
>   KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 redistributor TYPER handler
>   KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
>   KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
>   KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
>   KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
>   KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
>   KVM: arm/arm64: vgic-new: implement mapped IRQ handling
>   KVM: arm/arm64: vgic-new: Add dummy MSI implementation
>   KVM: arm/arm64: vgic-new: enable build
>
> Christoffer Dall (5):
>   KVM: arm/arm64: vgic-new: Add data structure definitions
>   KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq
>     instance
>   KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
>   KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity
>   KVM: arm/arm64: vgic-new: Add IRQ sorting
>
> Eric Auger (12):
>   KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
>   KVM: arm/arm64: vgic-new: vgic_kvm_device:
>     KVM_DEV_ARM_VGIC_GRP_NR_IRQS
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
>   KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
>   KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
>   KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
>   KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
>   KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
>
> Marc Zyngier (2):
>   KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
>   KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
>
>  arch/arm/kvm/Kconfig                |    7 +
>  arch/arm/kvm/Makefile               |   10 +
>  arch/arm/kvm/mmio.c                 |    2 +-
>  arch/arm64/kvm/Kconfig              |    7 +
>  arch/arm64/kvm/Makefile             |   10 +
>  include/kvm/arm_vgic.h              |   14 +-
>  include/kvm/vgic/vgic.h             |  256 +++++++
>  virt/kvm/arm/arch_timer.c           |   11 +-
>  virt/kvm/arm/pmu.c                  |    2 +-
>  virt/kvm/arm/vgic.c                 |   18 +-
>  virt/kvm/arm/vgic/vgic-v2.c         |  381 +++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c         |  357 ++++++++++
>  virt/kvm/arm/vgic/vgic.c            |  614 +++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |  136 ++++
>  virt/kvm/arm/vgic/vgic_init.c       |  447 ++++++++++++
>  virt/kvm/arm/vgic/vgic_irqfd.c      |   51 ++
>  virt/kvm/arm/vgic/vgic_kvm_device.c |  522 ++++++++++++++
>  virt/kvm/arm/vgic/vgic_mmio.c       | 1277 +++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic_mmio.h       |   47 ++
>  19 files changed, 4149 insertions(+), 20 deletions(-)
>  create mode 100644 include/kvm/vgic/vgic.h
>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.h
>  create mode 100644 virt/kvm/arm/vgic/vgic_init.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_kvm_device.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
>

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-25 15:58   ` Diana Madalina Craciun
  0 siblings, 0 replies; 276+ messages in thread
From: Diana Madalina Craciun @ 2016-03-25 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andre,

On which kernel version should I apply these series ?

Thanks,

Diana

On 03/25/2016 04:05 AM, Andre Przywara wrote:
> This series is a joint effort to re-implement KVM's GIC emulation.
>
> While the current implementation is centered around providing
> efficient MMIO emulation, the hot path for most guests is actually
> the guest entry and exit, which currently is rather costly.
> Also the existing emulation has a global distributor lock, which
> quickly becomes a bottleneck once the number of VCPUs increases.
> Additionally the emulation was originally designed for GICv2, adding
> GICv3 ITS emulation support to this proved to be rather painful.
> Last, but not least the existing code became less and less
> maintainable, with many special cases handled explicitly.
>
> The new implementation is build around a struct vgic_irq data data
> structure, which holds all information about a virtual interrupt.
> Interruts which should be injected are hold in a per-VCPU list, this
> make the entry/exit path much more efficient. Also the new structure
> allows to have more fine grained locking - per IRQ and per VCPU -
> getting rid of the global distributor lock.
> As a result of the new design ITS emulation fits in more nicely, the
> respective code will be provided as a follow-up series.
>
> This series implements the same feature set as the existing emulation,
> as a goodie we now implement priorities correctly.
> To allow an easy transition with good test coverage, but still maintain
> stability, both implementations live side by side, selectable via a
> Kconfig option. The default is the new implementation.
> If this code proves to be reliable, we will later remove the current
> implementation with an extra patch set.
>
> Please have a look at the series, review it and give the code some
> serious testing (and possibly debugging). All feedback is appreciated.
>
> Cheers,
> Andre.
>
> Andre Przywara (26):
>   KVM: arm/arm64: add missing MMIO data write-back
>   KVM: arm/arm64: pmu: abstract access to number of SPIs
>   KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface
>   KVM: arm/arm64: vgic-new: Add MMIO handling framework
>   KVM: arm/arm64: vgic-new: Export register access interface
>   KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
>   KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
>   KVM: arm/arm64: vgic-new: Add PENDING registers handlers
>   KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
>   KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
>   KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
>   KVM: arm/arm64: vgic-new: Add TARGET registers handlers
>   KVM: arm/arm64: vgic-new: Add SGIR register handler
>   KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
>   KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 redistributor TYPER handler
>   KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
>   KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
>   KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
>   KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
>   KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
>   KVM: arm/arm64: vgic-new: implement mapped IRQ handling
>   KVM: arm/arm64: vgic-new: Add dummy MSI implementation
>   KVM: arm/arm64: vgic-new: enable build
>
> Christoffer Dall (5):
>   KVM: arm/arm64: vgic-new: Add data structure definitions
>   KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq
>     instance
>   KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
>   KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity
>   KVM: arm/arm64: vgic-new: Add IRQ sorting
>
> Eric Auger (12):
>   KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
>   KVM: arm/arm64: vgic-new: vgic_kvm_device:
>     KVM_DEV_ARM_VGIC_GRP_NR_IRQS
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
>   KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
>   KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
>   KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
>   KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
>   KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
>
> Marc Zyngier (2):
>   KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
>   KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
>
>  arch/arm/kvm/Kconfig                |    7 +
>  arch/arm/kvm/Makefile               |   10 +
>  arch/arm/kvm/mmio.c                 |    2 +-
>  arch/arm64/kvm/Kconfig              |    7 +
>  arch/arm64/kvm/Makefile             |   10 +
>  include/kvm/arm_vgic.h              |   14 +-
>  include/kvm/vgic/vgic.h             |  256 +++++++
>  virt/kvm/arm/arch_timer.c           |   11 +-
>  virt/kvm/arm/pmu.c                  |    2 +-
>  virt/kvm/arm/vgic.c                 |   18 +-
>  virt/kvm/arm/vgic/vgic-v2.c         |  381 +++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c         |  357 ++++++++++
>  virt/kvm/arm/vgic/vgic.c            |  614 +++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |  136 ++++
>  virt/kvm/arm/vgic/vgic_init.c       |  447 ++++++++++++
>  virt/kvm/arm/vgic/vgic_irqfd.c      |   51 ++
>  virt/kvm/arm/vgic/vgic_kvm_device.c |  522 ++++++++++++++
>  virt/kvm/arm/vgic/vgic_mmio.c       | 1277 +++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic_mmio.h       |   47 ++
>  19 files changed, 4149 insertions(+), 20 deletions(-)
>  create mode 100644 include/kvm/vgic/vgic.h
>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.h
>  create mode 100644 virt/kvm/arm/vgic/vgic_init.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_kvm_device.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
>

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-26  2:11   ` André Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: André Przywara @ 2016-03-26  2:11 UTC (permalink / raw)
  To: Diana Madalina Craciun, lkp
  Cc: Christoffer Dall, Marc Zyngier, Eric Auger, kvmarm, kvm,
	linux-arm-kernel

On 25/03/16 02:04, Andre Przywara wrote:
> This series is a joint effort to re-implement KVM's GIC emulation.

Forgot to mention:
This series is based on an older version of kvmarm.git/next, which is
roughly the pull request that got merged into 4.6-rc0. It applies to the
current master, so I suggest people use 4.6-rc1 as a base once this is
released.

A git tree containing this series and the prerequisites can be found on
linux-arm.org:

git://linux-arm.org/linux-ap.git
http://www.linux-arm.org/git?p=linux-ap.git;a=log;h=refs/heads/vgic-new/rfc

Cheers,
Andre.

> 
> While the current implementation is centered around providing
> efficient MMIO emulation, the hot path for most guests is actually
> the guest entry and exit, which currently is rather costly.
> Also the existing emulation has a global distributor lock, which
> quickly becomes a bottleneck once the number of VCPUs increases.
> Additionally the emulation was originally designed for GICv2, adding
> GICv3 ITS emulation support to this proved to be rather painful.
> Last, but not least the existing code became less and less
> maintainable, with many special cases handled explicitly.
> 
> The new implementation is build around a struct vgic_irq data data
> structure, which holds all information about a virtual interrupt.
> Interruts which should be injected are hold in a per-VCPU list, this
> make the entry/exit path much more efficient. Also the new structure
> allows to have more fine grained locking - per IRQ and per VCPU -
> getting rid of the global distributor lock.
> As a result of the new design ITS emulation fits in more nicely, the
> respective code will be provided as a follow-up series.
> 
> This series implements the same feature set as the existing emulation,
> as a goodie we now implement priorities correctly.
> To allow an easy transition with good test coverage, but still maintain
> stability, both implementations live side by side, selectable via a
> Kconfig option. The default is the new implementation.
> If this code proves to be reliable, we will later remove the current
> implementation with an extra patch set.
> 
> Please have a look at the series, review it and give the code some
> serious testing (and possibly debugging). All feedback is appreciated.
> 
> Cheers,
> Andre.
> 
> Andre Przywara (26):
>   KVM: arm/arm64: add missing MMIO data write-back
>   KVM: arm/arm64: pmu: abstract access to number of SPIs
>   KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface
>   KVM: arm/arm64: vgic-new: Add MMIO handling framework
>   KVM: arm/arm64: vgic-new: Export register access interface
>   KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
>   KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
>   KVM: arm/arm64: vgic-new: Add PENDING registers handlers
>   KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
>   KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
>   KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
>   KVM: arm/arm64: vgic-new: Add TARGET registers handlers
>   KVM: arm/arm64: vgic-new: Add SGIR register handler
>   KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
>   KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 redistributor TYPER handler
>   KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
>   KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
>   KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
>   KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
>   KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
>   KVM: arm/arm64: vgic-new: implement mapped IRQ handling
>   KVM: arm/arm64: vgic-new: Add dummy MSI implementation
>   KVM: arm/arm64: vgic-new: enable build
> 
> Christoffer Dall (5):
>   KVM: arm/arm64: vgic-new: Add data structure definitions
>   KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq
>     instance
>   KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
>   KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity
>   KVM: arm/arm64: vgic-new: Add IRQ sorting
> 
> Eric Auger (12):
>   KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
>   KVM: arm/arm64: vgic-new: vgic_kvm_device:
>     KVM_DEV_ARM_VGIC_GRP_NR_IRQS
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
>   KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
>   KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
>   KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
>   KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
>   KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
> 
> Marc Zyngier (2):
>   KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
>   KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
> 
>  arch/arm/kvm/Kconfig                |    7 +
>  arch/arm/kvm/Makefile               |   10 +
>  arch/arm/kvm/mmio.c                 |    2 +-
>  arch/arm64/kvm/Kconfig              |    7 +
>  arch/arm64/kvm/Makefile             |   10 +
>  include/kvm/arm_vgic.h              |   14 +-
>  include/kvm/vgic/vgic.h             |  256 +++++++
>  virt/kvm/arm/arch_timer.c           |   11 +-
>  virt/kvm/arm/pmu.c                  |    2 +-
>  virt/kvm/arm/vgic.c                 |   18 +-
>  virt/kvm/arm/vgic/vgic-v2.c         |  381 +++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c         |  357 ++++++++++
>  virt/kvm/arm/vgic/vgic.c            |  614 +++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |  136 ++++
>  virt/kvm/arm/vgic/vgic_init.c       |  447 ++++++++++++
>  virt/kvm/arm/vgic/vgic_irqfd.c      |   51 ++
>  virt/kvm/arm/vgic/vgic_kvm_device.c |  522 ++++++++++++++
>  virt/kvm/arm/vgic/vgic_mmio.c       | 1277 +++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic_mmio.h       |   47 ++
>  19 files changed, 4149 insertions(+), 20 deletions(-)
>  create mode 100644 include/kvm/vgic/vgic.h
>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.h
>  create mode 100644 virt/kvm/arm/vgic/vgic_init.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_kvm_device.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
> 


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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-26  2:11   ` André Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: André Przywara @ 2016-03-26  2:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 25/03/16 02:04, Andre Przywara wrote:
> This series is a joint effort to re-implement KVM's GIC emulation.

Forgot to mention:
This series is based on an older version of kvmarm.git/next, which is
roughly the pull request that got merged into 4.6-rc0. It applies to the
current master, so I suggest people use 4.6-rc1 as a base once this is
released.

A git tree containing this series and the prerequisites can be found on
linux-arm.org:

git://linux-arm.org/linux-ap.git
http://www.linux-arm.org/git?p=linux-ap.git;a=log;h=refs/heads/vgic-new/rfc

Cheers,
Andre.

> 
> While the current implementation is centered around providing
> efficient MMIO emulation, the hot path for most guests is actually
> the guest entry and exit, which currently is rather costly.
> Also the existing emulation has a global distributor lock, which
> quickly becomes a bottleneck once the number of VCPUs increases.
> Additionally the emulation was originally designed for GICv2, adding
> GICv3 ITS emulation support to this proved to be rather painful.
> Last, but not least the existing code became less and less
> maintainable, with many special cases handled explicitly.
> 
> The new implementation is build around a struct vgic_irq data data
> structure, which holds all information about a virtual interrupt.
> Interruts which should be injected are hold in a per-VCPU list, this
> make the entry/exit path much more efficient. Also the new structure
> allows to have more fine grained locking - per IRQ and per VCPU -
> getting rid of the global distributor lock.
> As a result of the new design ITS emulation fits in more nicely, the
> respective code will be provided as a follow-up series.
> 
> This series implements the same feature set as the existing emulation,
> as a goodie we now implement priorities correctly.
> To allow an easy transition with good test coverage, but still maintain
> stability, both implementations live side by side, selectable via a
> Kconfig option. The default is the new implementation.
> If this code proves to be reliable, we will later remove the current
> implementation with an extra patch set.
> 
> Please have a look at the series, review it and give the code some
> serious testing (and possibly debugging). All feedback is appreciated.
> 
> Cheers,
> Andre.
> 
> Andre Przywara (26):
>   KVM: arm/arm64: add missing MMIO data write-back
>   KVM: arm/arm64: pmu: abstract access to number of SPIs
>   KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface
>   KVM: arm/arm64: vgic-new: Add MMIO handling framework
>   KVM: arm/arm64: vgic-new: Export register access interface
>   KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
>   KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
>   KVM: arm/arm64: vgic-new: Add PENDING registers handlers
>   KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
>   KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
>   KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
>   KVM: arm/arm64: vgic-new: Add TARGET registers handlers
>   KVM: arm/arm64: vgic-new: Add SGIR register handler
>   KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
>   KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 redistributor TYPER handler
>   KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
>   KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
>   KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
>   KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
>   KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
>   KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
>   KVM: arm/arm64: vgic-new: implement mapped IRQ handling
>   KVM: arm/arm64: vgic-new: Add dummy MSI implementation
>   KVM: arm/arm64: vgic-new: enable build
> 
> Christoffer Dall (5):
>   KVM: arm/arm64: vgic-new: Add data structure definitions
>   KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq
>     instance
>   KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
>   KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity
>   KVM: arm/arm64: vgic-new: Add IRQ sorting
> 
> Eric Auger (12):
>   KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
>   KVM: arm/arm64: vgic-new: vgic_kvm_device:
>     KVM_DEV_ARM_VGIC_GRP_NR_IRQS
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
>   KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
>   KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
>   KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
>   KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
>   KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
>   KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
> 
> Marc Zyngier (2):
>   KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
>   KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
> 
>  arch/arm/kvm/Kconfig                |    7 +
>  arch/arm/kvm/Makefile               |   10 +
>  arch/arm/kvm/mmio.c                 |    2 +-
>  arch/arm64/kvm/Kconfig              |    7 +
>  arch/arm64/kvm/Makefile             |   10 +
>  include/kvm/arm_vgic.h              |   14 +-
>  include/kvm/vgic/vgic.h             |  256 +++++++
>  virt/kvm/arm/arch_timer.c           |   11 +-
>  virt/kvm/arm/pmu.c                  |    2 +-
>  virt/kvm/arm/vgic.c                 |   18 +-
>  virt/kvm/arm/vgic/vgic-v2.c         |  381 +++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c         |  357 ++++++++++
>  virt/kvm/arm/vgic/vgic.c            |  614 +++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |  136 ++++
>  virt/kvm/arm/vgic/vgic_init.c       |  447 ++++++++++++
>  virt/kvm/arm/vgic/vgic_irqfd.c      |   51 ++
>  virt/kvm/arm/vgic/vgic_kvm_device.c |  522 ++++++++++++++
>  virt/kvm/arm/vgic/vgic_mmio.c       | 1277 +++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic_mmio.h       |   47 ++
>  19 files changed, 4149 insertions(+), 20 deletions(-)
>  create mode 100644 include/kvm/vgic/vgic.h
>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.h
>  create mode 100644 virt/kvm/arm/vgic/vgic_init.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_kvm_device.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
> 

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

* Re: [RFC PATCH 01/45] KVM: arm/arm64: add missing MMIO data write-back
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-29 12:33     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-29 12:33 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:24AM +0000, Andre Przywara wrote:
> When the kernel was handling a guest MMIO access internally, we need
> to copy the emulation result into the run->mmio structure in order
> for the kvm_handle_mmio_return() function to pick it up and inject
> the result back into the guest.
> Currently the only user of kvm_io_bus for ARM is the VGIC, which did
> this copying itself, so this was not causing issues so far.
> But with upcoming kvm_io_bus users we need to do the copying here.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  arch/arm/kvm/mmio.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
> index 0f6600f..d5c2727 100644
> --- a/arch/arm/kvm/mmio.c
> +++ b/arch/arm/kvm/mmio.c
> @@ -206,7 +206,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>  	run->mmio.is_write	= is_write;
>  	run->mmio.phys_addr	= fault_ipa;
>  	run->mmio.len		= len;
> -	if (is_write)
> +	if (is_write || !ret)
>  		memcpy(run->mmio.data, data_buf, len);

I had a really hard time understanding this, how about this instead:

diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 0f6600f..0158e9e 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
 
 /**
  * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
+ *			     or in-kernel IO emulation
+ *
  * @vcpu: The VCPU pointer
  * @run:  The VCPU run struct containing the mmio data
- *
- * This should only be called after returning from userspace for MMIO load
- * emulation.
  */
 int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
@@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	run->mmio.is_write	= is_write;
 	run->mmio.phys_addr	= fault_ipa;
 	run->mmio.len		= len;
-	if (is_write)
-		memcpy(run->mmio.data, data_buf, len);
 
 	if (!ret) {
 		/* We handled the access successfully in the kernel. */
+		if (!is_write)
+			memcpy(run->mmio.data, data_buf, len);
 		vcpu->stat.mmio_exit_kernel++;
 		kvm_handle_mmio_return(vcpu, run);
 		return 1;
-	} else {
-		vcpu->stat.mmio_exit_user++;
 	}
 
+	if (is_write)
+		memcpy(run->mmio.data, data_buf, len);
+	vcpu->stat.mmio_exit_user++;
 	run->exit_reason	= KVM_EXIT_MMIO;
 	return 0;
 }
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00429b3..63e99cb 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -850,12 +850,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
 		updated_state = false;
 	}
 	spin_unlock(&dist->lock);
-	run->mmio.is_write	= is_write;
-	run->mmio.len		= len;
-	run->mmio.phys_addr	= addr;
-	memcpy(run->mmio.data, val, len);
-
-	kvm_handle_mmio_return(vcpu, run);
 
 	if (updated_state)
 		vgic_kick_vcpus(vcpu->kvm);

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

* [RFC PATCH 01/45] KVM: arm/arm64: add missing MMIO data write-back
@ 2016-03-29 12:33     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-29 12:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:24AM +0000, Andre Przywara wrote:
> When the kernel was handling a guest MMIO access internally, we need
> to copy the emulation result into the run->mmio structure in order
> for the kvm_handle_mmio_return() function to pick it up and inject
> the result back into the guest.
> Currently the only user of kvm_io_bus for ARM is the VGIC, which did
> this copying itself, so this was not causing issues so far.
> But with upcoming kvm_io_bus users we need to do the copying here.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  arch/arm/kvm/mmio.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
> index 0f6600f..d5c2727 100644
> --- a/arch/arm/kvm/mmio.c
> +++ b/arch/arm/kvm/mmio.c
> @@ -206,7 +206,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>  	run->mmio.is_write	= is_write;
>  	run->mmio.phys_addr	= fault_ipa;
>  	run->mmio.len		= len;
> -	if (is_write)
> +	if (is_write || !ret)
>  		memcpy(run->mmio.data, data_buf, len);

I had a really hard time understanding this, how about this instead:

diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 0f6600f..0158e9e 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
 
 /**
  * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
+ *			     or in-kernel IO emulation
+ *
  * @vcpu: The VCPU pointer
  * @run:  The VCPU run struct containing the mmio data
- *
- * This should only be called after returning from userspace for MMIO load
- * emulation.
  */
 int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
@@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	run->mmio.is_write	= is_write;
 	run->mmio.phys_addr	= fault_ipa;
 	run->mmio.len		= len;
-	if (is_write)
-		memcpy(run->mmio.data, data_buf, len);
 
 	if (!ret) {
 		/* We handled the access successfully in the kernel. */
+		if (!is_write)
+			memcpy(run->mmio.data, data_buf, len);
 		vcpu->stat.mmio_exit_kernel++;
 		kvm_handle_mmio_return(vcpu, run);
 		return 1;
-	} else {
-		vcpu->stat.mmio_exit_user++;
 	}
 
+	if (is_write)
+		memcpy(run->mmio.data, data_buf, len);
+	vcpu->stat.mmio_exit_user++;
 	run->exit_reason	= KVM_EXIT_MMIO;
 	return 0;
 }
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00429b3..63e99cb 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -850,12 +850,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
 		updated_state = false;
 	}
 	spin_unlock(&dist->lock);
-	run->mmio.is_write	= is_write;
-	run->mmio.len		= len;
-	run->mmio.phys_addr	= addr;
-	memcpy(run->mmio.data, val, len);
-
-	kvm_handle_mmio_return(vcpu, run);
 
 	if (updated_state)
 		vgic_kick_vcpus(vcpu->kvm);

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

* Re: [RFC PATCH 03/45] KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-29 13:01     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-29 13:01 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:26AM +0000, Andre Przywara wrote:
> Adapt the interface between the virtualized arch timer and the
> emulated VGIC to avoid the phys_map when possible.
> This prepares the arch timer to go with both the existing VGIC
> implementation and the new version later without too many code
> changes.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h    |  7 ++++---
>  virt/kvm/arm/arch_timer.c | 11 +++++------
>  virt/kvm/arm/vgic.c       | 18 +++++++++---------
>  3 files changed, 18 insertions(+), 18 deletions(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 2b89e27..7656a46 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -345,13 +345,14 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
>  			bool level);
>  int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
> -			       struct irq_phys_map *map, bool level);
> +			       int virt_irq, bool level);
>  void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
>  					   int virt_irq, int irq);
> -int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
> -bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
> +			    int virt_irq);

I don't understand the benefit of this change.  You're now passing the
virt_irq in both the struct and as a parameter.

If you want to get rid of the irq_phys_map structure, just replace all
occurences of it with two parameters/arguments instead, int virt_irq,
int phys_irq, both of which are INTIDs.

You don't need to pass the Linux IRQ number from outside the vgic to the
vgic anymore, and it's just there for historical reasons, so you can
remove that with a separate patch if you want.

If you want me to send a patch removing the IRQ field, let me know.  It
looks something like this:

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 281caf8..9ffe29c 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -157,7 +157,6 @@ struct vgic_io_device {
 struct irq_phys_map {
 	u32			virt_irq;
 	u32			phys_irq;
-	u32			irq;
 };
 
 struct irq_phys_map_entry {
@@ -345,7 +344,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int irq);
+					   int virt_irq, int phys_irq);
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
 
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index a9ad4fe..73ca3e5 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -274,7 +274,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	if (timer->active_cleared_last && !phys_active)
 		return;
 
-	ret = irq_set_irqchip_state(timer->map->irq,
+	ret = irq_set_irqchip_state(host_vtimer_irq,
 				    IRQCHIP_STATE_ACTIVE,
 				    phys_active);
 	WARN_ON(ret);
@@ -307,6 +307,9 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 	struct irq_phys_map *map;
+	struct irq_desc *desc;
+	struct irq_data *data;
+	int phys_irq;
 
 	/*
 	 * The vcpu timer irq number cannot be determined in
@@ -326,10 +329,25 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 	kvm_timer_update_state(vcpu);
 
 	/*
+	 * Find the physical IRQ number corresponding to the host_vtimer_irq
+	 */
+	desc = irq_to_desc(host_vtimer_irq);
+	if (!desc) {
+		kvm_err("%s: no interrupt descriptor\n", __func__);
+		return -EINVAL;
+	}
+
+	data = irq_desc_get_irq_data(desc);
+	while (data->parent_data)
+		data = data->parent_data;
+
+	phys_irq = data->hwirq;
+
+	/*
 	 * Tell the VGIC that the virtual interrupt is tied to a
 	 * physical interrupt. We do that once per VCPU.
 	 */
-	map = kvm_vgic_map_phys_irq(vcpu, irq->irq, host_vtimer_irq);
+	map = kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
 	if (WARN_ON(IS_ERR(map)))
 		return PTR_ERR(map);
 
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00429b3..012f428 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1724,27 +1724,13 @@ static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu,
  * Returns a valid pointer on success, and an error pointer otherwise
  */
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int irq)
+					   int virt_irq, int phys_irq)
 {
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct list_head *root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
 	struct irq_phys_map *map;
 	struct irq_phys_map_entry *entry;
-	struct irq_desc *desc;
-	struct irq_data *data;
-	int phys_irq;
 
-	desc = irq_to_desc(irq);
-	if (!desc) {
-		kvm_err("%s: no interrupt descriptor\n", __func__);
-		return ERR_PTR(-EINVAL);
-	}
-
-	data = irq_desc_get_irq_data(desc);
-	while (data->parent_data)
-		data = data->parent_data;
-
-	phys_irq = data->hwirq;
 
 	/* Create a new mapping */
 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
@@ -1757,8 +1743,7 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 	map = vgic_irq_map_search(vcpu, virt_irq);
 	if (map) {
 		/* Make sure this mapping matches */
-		if (map->phys_irq != phys_irq	||
-		    map->irq      != irq)
+		if (map->phys_irq != phys_irq)
 			map = ERR_PTR(-EINVAL);
 
 		/* Found an existing, valid mapping */
@@ -1768,7 +1753,6 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 	map           = &entry->map;
 	map->virt_irq = virt_irq;
 	map->phys_irq = phys_irq;
-	map->irq      = irq;
 
 	list_add_tail_rcu(&entry->entry, root);
 


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

* [RFC PATCH 03/45] KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface
@ 2016-03-29 13:01     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-29 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:26AM +0000, Andre Przywara wrote:
> Adapt the interface between the virtualized arch timer and the
> emulated VGIC to avoid the phys_map when possible.
> This prepares the arch timer to go with both the existing VGIC
> implementation and the new version later without too many code
> changes.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h    |  7 ++++---
>  virt/kvm/arm/arch_timer.c | 11 +++++------
>  virt/kvm/arm/vgic.c       | 18 +++++++++---------
>  3 files changed, 18 insertions(+), 18 deletions(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 2b89e27..7656a46 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -345,13 +345,14 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
>  			bool level);
>  int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
> -			       struct irq_phys_map *map, bool level);
> +			       int virt_irq, bool level);
>  void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
>  					   int virt_irq, int irq);
> -int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
> -bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
> +			    int virt_irq);

I don't understand the benefit of this change.  You're now passing the
virt_irq in both the struct and as a parameter.

If you want to get rid of the irq_phys_map structure, just replace all
occurences of it with two parameters/arguments instead, int virt_irq,
int phys_irq, both of which are INTIDs.

You don't need to pass the Linux IRQ number from outside the vgic to the
vgic anymore, and it's just there for historical reasons, so you can
remove that with a separate patch if you want.

If you want me to send a patch removing the IRQ field, let me know.  It
looks something like this:

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 281caf8..9ffe29c 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -157,7 +157,6 @@ struct vgic_io_device {
 struct irq_phys_map {
 	u32			virt_irq;
 	u32			phys_irq;
-	u32			irq;
 };
 
 struct irq_phys_map_entry {
@@ -345,7 +344,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int irq);
+					   int virt_irq, int phys_irq);
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
 
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index a9ad4fe..73ca3e5 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -274,7 +274,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	if (timer->active_cleared_last && !phys_active)
 		return;
 
-	ret = irq_set_irqchip_state(timer->map->irq,
+	ret = irq_set_irqchip_state(host_vtimer_irq,
 				    IRQCHIP_STATE_ACTIVE,
 				    phys_active);
 	WARN_ON(ret);
@@ -307,6 +307,9 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 	struct irq_phys_map *map;
+	struct irq_desc *desc;
+	struct irq_data *data;
+	int phys_irq;
 
 	/*
 	 * The vcpu timer irq number cannot be determined in
@@ -326,10 +329,25 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 	kvm_timer_update_state(vcpu);
 
 	/*
+	 * Find the physical IRQ number corresponding to the host_vtimer_irq
+	 */
+	desc = irq_to_desc(host_vtimer_irq);
+	if (!desc) {
+		kvm_err("%s: no interrupt descriptor\n", __func__);
+		return -EINVAL;
+	}
+
+	data = irq_desc_get_irq_data(desc);
+	while (data->parent_data)
+		data = data->parent_data;
+
+	phys_irq = data->hwirq;
+
+	/*
 	 * Tell the VGIC that the virtual interrupt is tied to a
 	 * physical interrupt. We do that once per VCPU.
 	 */
-	map = kvm_vgic_map_phys_irq(vcpu, irq->irq, host_vtimer_irq);
+	map = kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
 	if (WARN_ON(IS_ERR(map)))
 		return PTR_ERR(map);
 
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00429b3..012f428 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1724,27 +1724,13 @@ static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu,
  * Returns a valid pointer on success, and an error pointer otherwise
  */
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int irq)
+					   int virt_irq, int phys_irq)
 {
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct list_head *root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
 	struct irq_phys_map *map;
 	struct irq_phys_map_entry *entry;
-	struct irq_desc *desc;
-	struct irq_data *data;
-	int phys_irq;
 
-	desc = irq_to_desc(irq);
-	if (!desc) {
-		kvm_err("%s: no interrupt descriptor\n", __func__);
-		return ERR_PTR(-EINVAL);
-	}
-
-	data = irq_desc_get_irq_data(desc);
-	while (data->parent_data)
-		data = data->parent_data;
-
-	phys_irq = data->hwirq;
 
 	/* Create a new mapping */
 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
@@ -1757,8 +1743,7 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 	map = vgic_irq_map_search(vcpu, virt_irq);
 	if (map) {
 		/* Make sure this mapping matches */
-		if (map->phys_irq != phys_irq	||
-		    map->irq      != irq)
+		if (map->phys_irq != phys_irq)
 			map = ERR_PTR(-EINVAL);
 
 		/* Found an existing, valid mapping */
@@ -1768,7 +1753,6 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 	map           = &entry->map;
 	map->virt_irq = virt_irq;
 	map->phys_irq = phys_irq;
-	map->irq      = irq;
 
 	list_add_tail_rcu(&entry->entry, root);
 

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

* Re: [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-29 13:09     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-29 13:09 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Add a new header file for the new and improved GIC implementation.
> The big change is that we now have a struct vgic_irq per IRQ instead
> of spreading all the information over various bitmaps.
> 
> We include this new header conditionally from within the old header
> file for the time being to avoid touching all the users.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h  |   5 ++
>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 203 insertions(+)
>  create mode 100644 include/kvm/vgic/vgic.h
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 7656a46..db289a2 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -19,6 +19,10 @@
>  #ifndef __ASM_ARM_KVM_VGIC_H
>  #define __ASM_ARM_KVM_VGIC_H
>  
> +#ifdef CONFIG_KVM_NEW_VGIC
> +#include <kvm/vgic/vgic.h>
> +#else
> +
>  #include <linux/kernel.h>
>  #include <linux/kvm.h>
>  #include <linux/irqreturn.h>
> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>  }
>  #endif
>  
> +#endif	/* old VGIC include */
>  #endif
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> new file mode 100644
> index 0000000..659f8b1
> --- /dev/null
> +++ b/include/kvm/vgic/vgic.h
> @@ -0,0 +1,198 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> +
> +#include <linux/kernel.h>
> +#include <linux/kvm.h>
> +#include <linux/irqreturn.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +#include <kvm/iodev.h>
> +
> +#define VGIC_V3_MAX_CPUS	255
> +#define VGIC_V2_MAX_CPUS	8
> +#define VGIC_NR_IRQS_LEGACY     256
> +#define VGIC_NR_SGIS		16
> +#define VGIC_NR_PPIS		16
> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> +#define VGIC_MAX_SPI		1019
> +#define VGIC_MAX_RESERVED	1023
> +#define VGIC_MIN_LPI		8192
> +
> +enum vgic_type {
> +	VGIC_V2,		/* Good ol' GICv2 */
> +	VGIC_V3,		/* New fancy GICv3 */
> +};
> +
> +/* same for all guests, as depending only on the _host's_ GIC model */
> +struct vgic_global {
> +	/* type of the host GIC */
> +	enum vgic_type		type;
> +
> +	/* Physical address of vgic virtual cpu interface */
> +	phys_addr_t		vcpu_base;
> +
> +	/* virtual control interface mapping */
> +	void __iomem		*vctrl_base;
> +
> +	/* Number of implemented list registers */
> +	int			nr_lr;
> +
> +	/* Maintenance IRQ number */
> +	unsigned int		maint_irq;
> +
> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> +	int			max_gic_vcpus;
> +
> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
> +	bool			can_emulate_gicv2;
> +};
> +
> +extern struct vgic_global kvm_vgic_global_state;
> +
> +#define VGIC_V2_MAX_LRS		(1 << 6)
> +#define VGIC_V3_MAX_LRS		16
> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
> +
> +enum vgic_irq_config {
> +	VGIC_CONFIG_EDGE = 0,
> +	VGIC_CONFIG_LEVEL
> +};
> +
> +struct vgic_irq {
> +	spinlock_t irq_lock;		/* Protects the content of the struct */
> +	struct list_head ap_list;
> +
> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
> +					 * SPIs and LPIs: The VCPU whose ap_list
> +					 * on which this is queued.
> +					 */
> +
> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
> +					 * be send to, as a result of the
> +					 * targets reg (v2) or the
> +					 * affinity reg (v3).
> +					 */
> +
> +	u32 intid;			/* Guest visible INTID */
> +	bool pending;
> +	bool line_level;		/* Level only */
> +	bool soft_pending;		/* Level only */
> +	bool active;			/* not used for LPIs */
> +	bool enabled;
> +	bool hw;			/* Tied to HW IRQ */
> +	u32 hwintid;			/* HW INTID number */
> +	union {
> +		u8 targets;			/* GICv2 target VCPUs mask */
> +		u32 mpidr;			/* GICv3 target VCPU */
> +	};
> +	u8 source;			/* GICv2 SGIs only */
> +	u8 priority;
> +	enum vgic_irq_config config;	/* Level or edge */
> +};
> +
> +struct vgic_dist {
> +	bool			in_kernel;
> +	bool			ready;
> +
> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> +	u32			vgic_model;
> +
> +	int			nr_spis;
> +
> +	/* TODO: Consider moving to global state */
> +	/* Virtual control interface mapping */
> +	void __iomem		*vctrl_base;
> +
> +	/* base addresses in guest physical address space: */
> +	gpa_t			vgic_dist_base;		/* distributor */
> +	union {
> +		/* either a GICv2 CPU interface */
> +		gpa_t			vgic_cpu_base;
> +		/* or a number of GICv3 redistributor regions */
> +		gpa_t			vgic_redist_base;
> +	};
> +
> +	/* distributor enabled */
> +	u32			enabled;
> +
> +	struct vgic_irq		*spis;
> +};
> +
> +struct vgic_v2_cpu_if {
> +	u32		vgic_hcr;
> +	u32		vgic_vmcr;
> +	u32		vgic_misr;	/* Saved only */
> +	u64		vgic_eisr;	/* Saved only */
> +	u64		vgic_elrsr;	/* Saved only */
> +	u32		vgic_apr;
> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
> +};
> +
> +struct vgic_v3_cpu_if {
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +	u32		vgic_hcr;
> +	u32		vgic_vmcr;
> +	u32		vgic_sre;	/* Restored only, change ignored */
> +	u32		vgic_misr;	/* Saved only */
> +	u32		vgic_eisr;	/* Saved only */
> +	u32		vgic_elrsr;	/* Saved only */
> +	u32		vgic_ap0r[4];
> +	u32		vgic_ap1r[4];
> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
> +#endif
> +};
> +
> +struct vgic_cpu {
> +	/* CPU vif control registers for world switch */
> +	union {
> +		struct vgic_v2_cpu_if	vgic_v2;
> +		struct vgic_v3_cpu_if	vgic_v3;
> +	};
> +
> +	/* TODO: Move nr_lr to a global state */

what is our current plan and status about this TODO?

> +	/* Number of list registers on this CPU */
> +	int		nr_lr;
> +
> +	unsigned int used_lrs;
> +	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
> +
> +	spinlock_t ap_list_lock;	/* Protects the ap_list */
> +
> +	/* list of IRQs for this VCPU to consider */

/*
 * List of IRQs that this VCPU should consider because they are either
 * Active or Pending (hence the name; AP list), or because they recently
 * were one of the two and need to be migrated off this list to another
 * VCPU.
 */

> +	struct list_head ap_list_head;
> +};
> +
> +#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> +#define vgic_initialized(k)	(false)
> +#define vgic_ready(k)		((k)->arch.vgic.ready)
> +#define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> +			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> +
> +/**
> + * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
> + *
> + * The host's GIC naturally limits the maximum amount of VCPUs a guest
> + * can use.
> + */
> +static inline int kvm_vgic_get_max_vcpus(void)
> +{
> +	return kvm_vgic_global_state.max_gic_vcpus;
> +}
> +
> +#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
> -- 
> 2.7.3
> 

Thanks,
-Christoffer

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

* [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-03-29 13:09     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-29 13:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Add a new header file for the new and improved GIC implementation.
> The big change is that we now have a struct vgic_irq per IRQ instead
> of spreading all the information over various bitmaps.
> 
> We include this new header conditionally from within the old header
> file for the time being to avoid touching all the users.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h  |   5 ++
>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 203 insertions(+)
>  create mode 100644 include/kvm/vgic/vgic.h
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 7656a46..db289a2 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -19,6 +19,10 @@
>  #ifndef __ASM_ARM_KVM_VGIC_H
>  #define __ASM_ARM_KVM_VGIC_H
>  
> +#ifdef CONFIG_KVM_NEW_VGIC
> +#include <kvm/vgic/vgic.h>
> +#else
> +
>  #include <linux/kernel.h>
>  #include <linux/kvm.h>
>  #include <linux/irqreturn.h>
> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>  }
>  #endif
>  
> +#endif	/* old VGIC include */
>  #endif
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> new file mode 100644
> index 0000000..659f8b1
> --- /dev/null
> +++ b/include/kvm/vgic/vgic.h
> @@ -0,0 +1,198 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> +
> +#include <linux/kernel.h>
> +#include <linux/kvm.h>
> +#include <linux/irqreturn.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +#include <kvm/iodev.h>
> +
> +#define VGIC_V3_MAX_CPUS	255
> +#define VGIC_V2_MAX_CPUS	8
> +#define VGIC_NR_IRQS_LEGACY     256
> +#define VGIC_NR_SGIS		16
> +#define VGIC_NR_PPIS		16
> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> +#define VGIC_MAX_SPI		1019
> +#define VGIC_MAX_RESERVED	1023
> +#define VGIC_MIN_LPI		8192
> +
> +enum vgic_type {
> +	VGIC_V2,		/* Good ol' GICv2 */
> +	VGIC_V3,		/* New fancy GICv3 */
> +};
> +
> +/* same for all guests, as depending only on the _host's_ GIC model */
> +struct vgic_global {
> +	/* type of the host GIC */
> +	enum vgic_type		type;
> +
> +	/* Physical address of vgic virtual cpu interface */
> +	phys_addr_t		vcpu_base;
> +
> +	/* virtual control interface mapping */
> +	void __iomem		*vctrl_base;
> +
> +	/* Number of implemented list registers */
> +	int			nr_lr;
> +
> +	/* Maintenance IRQ number */
> +	unsigned int		maint_irq;
> +
> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> +	int			max_gic_vcpus;
> +
> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
> +	bool			can_emulate_gicv2;
> +};
> +
> +extern struct vgic_global kvm_vgic_global_state;
> +
> +#define VGIC_V2_MAX_LRS		(1 << 6)
> +#define VGIC_V3_MAX_LRS		16
> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
> +
> +enum vgic_irq_config {
> +	VGIC_CONFIG_EDGE = 0,
> +	VGIC_CONFIG_LEVEL
> +};
> +
> +struct vgic_irq {
> +	spinlock_t irq_lock;		/* Protects the content of the struct */
> +	struct list_head ap_list;
> +
> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
> +					 * SPIs and LPIs: The VCPU whose ap_list
> +					 * on which this is queued.
> +					 */
> +
> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
> +					 * be send to, as a result of the
> +					 * targets reg (v2) or the
> +					 * affinity reg (v3).
> +					 */
> +
> +	u32 intid;			/* Guest visible INTID */
> +	bool pending;
> +	bool line_level;		/* Level only */
> +	bool soft_pending;		/* Level only */
> +	bool active;			/* not used for LPIs */
> +	bool enabled;
> +	bool hw;			/* Tied to HW IRQ */
> +	u32 hwintid;			/* HW INTID number */
> +	union {
> +		u8 targets;			/* GICv2 target VCPUs mask */
> +		u32 mpidr;			/* GICv3 target VCPU */
> +	};
> +	u8 source;			/* GICv2 SGIs only */
> +	u8 priority;
> +	enum vgic_irq_config config;	/* Level or edge */
> +};
> +
> +struct vgic_dist {
> +	bool			in_kernel;
> +	bool			ready;
> +
> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> +	u32			vgic_model;
> +
> +	int			nr_spis;
> +
> +	/* TODO: Consider moving to global state */
> +	/* Virtual control interface mapping */
> +	void __iomem		*vctrl_base;
> +
> +	/* base addresses in guest physical address space: */
> +	gpa_t			vgic_dist_base;		/* distributor */
> +	union {
> +		/* either a GICv2 CPU interface */
> +		gpa_t			vgic_cpu_base;
> +		/* or a number of GICv3 redistributor regions */
> +		gpa_t			vgic_redist_base;
> +	};
> +
> +	/* distributor enabled */
> +	u32			enabled;
> +
> +	struct vgic_irq		*spis;
> +};
> +
> +struct vgic_v2_cpu_if {
> +	u32		vgic_hcr;
> +	u32		vgic_vmcr;
> +	u32		vgic_misr;	/* Saved only */
> +	u64		vgic_eisr;	/* Saved only */
> +	u64		vgic_elrsr;	/* Saved only */
> +	u32		vgic_apr;
> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
> +};
> +
> +struct vgic_v3_cpu_if {
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +	u32		vgic_hcr;
> +	u32		vgic_vmcr;
> +	u32		vgic_sre;	/* Restored only, change ignored */
> +	u32		vgic_misr;	/* Saved only */
> +	u32		vgic_eisr;	/* Saved only */
> +	u32		vgic_elrsr;	/* Saved only */
> +	u32		vgic_ap0r[4];
> +	u32		vgic_ap1r[4];
> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
> +#endif
> +};
> +
> +struct vgic_cpu {
> +	/* CPU vif control registers for world switch */
> +	union {
> +		struct vgic_v2_cpu_if	vgic_v2;
> +		struct vgic_v3_cpu_if	vgic_v3;
> +	};
> +
> +	/* TODO: Move nr_lr to a global state */

what is our current plan and status about this TODO?

> +	/* Number of list registers on this CPU */
> +	int		nr_lr;
> +
> +	unsigned int used_lrs;
> +	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
> +
> +	spinlock_t ap_list_lock;	/* Protects the ap_list */
> +
> +	/* list of IRQs for this VCPU to consider */

/*
 * List of IRQs that this VCPU should consider because they are either
 * Active or Pending (hence the name; AP list), or because they recently
 * were one of the two and need to be migrated off this list to another
 * VCPU.
 */

> +	struct list_head ap_list_head;
> +};
> +
> +#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> +#define vgic_initialized(k)	(false)
> +#define vgic_ready(k)		((k)->arch.vgic.ready)
> +#define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> +			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> +
> +/**
> + * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
> + *
> + * The host's GIC naturally limits the maximum amount of VCPUs a guest
> + * can use.
> + */
> +static inline int kvm_vgic_get_max_vcpus(void)
> +{
> +	return kvm_vgic_global_state.max_gic_vcpus;
> +}
> +
> +#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
> -- 
> 2.7.3
> 

Thanks,
-Christoffer

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-29 13:12   ` Vladimir Murzin
  -1 siblings, 0 replies; 276+ messages in thread
From: Vladimir Murzin @ 2016-03-29 13:12 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall, Marc Zyngier, Eric Auger
  Cc: linux-arm-kernel, kvmarm, kvm

Hi Andre,

On 25/03/16 02:04, Andre Przywara wrote:
> Please have a look at the series, review it and give the code some
> serious testing (and possibly debugging). All feedback is appreciated.

I see that with the new vgic implementation kvmtool starts throwing:

kvm [1273]: Unable to register VGICv3 redist MMIO regions

for --cpus 58 and above, where with the old vgic it is quite happy with
up to 255 cpus.

Cheers
Vladimir

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-29 13:12   ` Vladimir Murzin
  0 siblings, 0 replies; 276+ messages in thread
From: Vladimir Murzin @ 2016-03-29 13:12 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andre,

On 25/03/16 02:04, Andre Przywara wrote:
> Please have a look at the series, review it and give the code some
> serious testing (and possibly debugging). All feedback is appreciated.

I see that with the new vgic implementation kvmtool starts throwing:

kvm [1273]: Unable to register VGICv3 redist MMIO regions

for --cpus 58 and above, where with the old vgic it is quite happy with
up to 255 cpus.

Cheers
Vladimir

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

* Re: [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-29 21:16     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-29 21:16 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:29AM +0000, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Provide a vgic_queue_irq() function which decides whether a given
> IRQ needs to be queued to a VCPU's ap_list.
> This should be called whenever an IRQ became pending or got enabled,

becomes pending or enabled,

> either as a result of userspace injection, from in-kernel emulated
> devices like the architected timer or from MMIO accesses to the
> distributor emulation.
> Also provides the necessary functions to allow userland to inject an
> IRQ to a guest.

Since this is the first code that starts using our locking mechanism, we
add some (hopefully) clear documentation of our locking strategy and
requirements along with this patch.

> [Andre: refactor out vgic_queue_irq()]
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h  |   3 +
>  virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   1 +
>  3 files changed, 185 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 659f8b1..f32b284 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -178,6 +178,9 @@ struct vgic_cpu {
>  	struct list_head ap_list_head;
>  };
>  
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level);
> +
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(false)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 8e34916..a95aabc 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -19,8 +19,25 @@
>  
>  #include "vgic.h"
>  
> +#define CREATE_TRACE_POINTS
> +#include "../trace.h"
> +
>  struct vgic_global kvm_vgic_global_state;
>  
> +/*
> + * Locking order is always:
> + *   vgic_cpu->ap_list_lock
> + *     vgic_irq->irq_lock
> + *
> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
> + *
> + * When taking more than one ap_list_lock at the same time, always take the
> + * lowest numbered VCPU's ap_list_lock first, so:
> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
> + */
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid)
>  {
> @@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>  	return NULL;
>  }
> +
> +/**
> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
> + *
> + * @irq:	The irq to route. Must be already locked.
> + *
> + * Based on the current state of the interrupt (enabled, pending,
> + * active, vcpu and target_vcpu), compute the next vcpu this should be
> + * given to. Return NULL if this shouldn't be injected at all.
> + */
> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
> +{
> +	/* If the interrupt is active, it must stay on the current vcpu */
> +	if (irq->active)
> +		return irq->vcpu;

we are not taking a lock here.  What are the locking expectations?  If
the expectarions are that the IRQ is locked when calling this function,
can we have a BIG FAT COMMENT saying that then?

It seems to me that we are somehow expecting irq->active and irq->vcpu
to be in sync, but that's not necessarily the case if the IRQ is not
locked.

> +
> +	/* If enabled and pending, it can migrate to a new one */

I think this comment should be rewritten to:

If the IRQ is not active but enabled and pending, we should direct it to
its configured target VCPU.

> +	if (irq->enabled && irq->pending)
> +		return irq->target_vcpu;
> +
> +	/* Otherwise, it is considered idle */

not sure what idle means here, I suggest something like:

If neither active nor pending and enabled, then this IRQ should not be
queued to any VCPU.

> +	return NULL;
> +}
> +
> +/*
> + * Only valid injection if changing level for level-triggered IRQs or for a
> + * rising edge.
> + */
> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
> +{
> +	switch (irq->config) {
> +	case VGIC_CONFIG_LEVEL:
> +		return irq->line_level != level;
> +	case VGIC_CONFIG_EDGE:
> +		return level;
> +	default:
> +		BUG();

is the default case there for making the compiler happy or can we just
get rid of it?

> +	}
> +}
> +
> +/*
> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
> + * Do the queuing if necessary, taking the right locks in the right order.
> + * Returns true when the IRQ was queued, false otherwise.
> + *
> + * Needs to be entered with the IRQ lock already held, but will return
> + * with all locks dropped.
> + */
> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)

should we name this vgic_try_queue_irq_locked ?

> +{
> +	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);

should we have something like BUG_ON(!spin_is_locked(irq->irq_lock));
here?

Not sure if there's some bug checking here which is only emitted if a
user select CONFIG_CHECK_SOME_LOCKING_THINGS that we could use...?

> +
> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
> +		/*
> +		 * If this IRQ is already on a VCPU's ap_list, then it
> +		 * cannot be moved or modified and there is no more work for
> +		 * us to do.
> +		 *
> +		 * Otherwise, if the irq is not pending and enabled, it does
> +		 * not need to be inserted into an ap_list and there is also
> +		 * no more work for us to do.
> +		 */

is the !vcpu check here not redundant because if you ever get to
evaluating it, then irq->vcpu is null, and pending and enabled are set,
which means the oracle couldn't have returned null, could it?

that would also explain why we don't have to re-check the same
conditions below...

or am I getting this wrong, because you could also have someone
explicitly setting the IRQ to active via trapped MMIO, in which case we
should be able to queue it without it being pending && enabled, which
would indicate that it's the other way around, you should only evaluate
!vcpu and kup the !(pending && enabled) part....?

> +		spin_unlock(&irq->irq_lock);
> +		return false;
> +	}
> +
> +	/*
> +	 * We must unlock the irq lock to take the ap_list_lock where
> +	 * we are going to insert this new pending interrupt.
> +	 */
> +	spin_unlock(&irq->irq_lock);
> +
> +	/* someone can do stuff here, which we re-check below */
> +retry:
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	spin_lock(&irq->irq_lock);
> +
> +	/*
> +	 * Did something change behind our backs?
> +	 *
> +	 * There are two cases:
> +	 * 1) The irq became pending or active behind our backs and/or
> +	 *    the irq->vcpu field was set correspondingly when putting
> +	 *    the irq on an ap_list. Then drop the locks and return.
> +	 * 2) Someone changed the affinity on this irq behind our
> +	 *    backs and we are now holding the wrong ap_list_lock.
> +	 *    Then drop the locks and try the new VCPU.
> +	 */
> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {

here I'm concerned about the active state again.

I feel like something more similar to my initial version of this patch
is what we really want:

       if (irq->vcpu || vcpu != vgic_target_oracle(irq))
           goto real_retry;

and read_retry is then a label at the very top of this function, before
the initial call to vgic_target_oracle()....

> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +		return false;
> +	}
> +
> +	if (irq->target_vcpu != vcpu) {
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +		vcpu = irq->target_vcpu;
> +		goto retry;
> +	}
> +
> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> +	irq->vcpu = vcpu;
> +
> +	spin_unlock(&irq->irq_lock);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +	kvm_vcpu_kick(vcpu);
> +
> +	return true;
> +}
> +
> +static void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +				    u32 intid, bool level)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
> +
> +	trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
> +
> +	BUG_ON(in_interrupt());

I don't remember why we thought it was a good idea to have this BUG_ON()
anymore.  Anyone?

> +
> +	spin_lock(&irq->irq_lock);
> +
> +	if (!vgic_validate_injection(irq, level)) {
> +		/* Nothing to see here, move along... */
> +		spin_unlock(&irq->irq_lock);
> +		return;
> +	}
> +
> +	if (irq->config == VGIC_CONFIG_LEVEL) {
> +		irq->line_level = level;
> +		irq->pending = level || irq->soft_pending;
> +	} else {
> +		irq->pending = true;
> +	}
> +
> +	vgic_queue_irq(kvm, irq);
> +}
> +
> +/**
> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
> + * @kvm:     The VM structure pointer
> + * @cpuid:   The CPU for PPIs
> + * @intid:   The INTID to inject a new state to.
> + *           must not be mapped to a HW interrupt.

stray line here?  I don't understand this bit about 'must not be mapped'
and I think that should be moved to the explanation below with some
rationale, and if important, perhaps guarded with a BUG_ON() ?

> + * @level:   Edge-triggered:  true:  to trigger the interrupt
> + *			      false: to ignore the call
> + *	     Level-sensitive  true:  raise the input signal
> + *			      false: lower the input signal
> + *
> + * The GIC is not concerned with devices being active-LOW or active-HIGH for

We should probably write VGIC here instead of GIC, just to avoid
confusion.

> + * level-sensitive interrupts.  You can think of the level parameter as 1
> + * being HIGH and 0 being LOW and all devices being active-HIGH.
> + */
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level)
> +{
> +	struct kvm_vcpu *vcpu;
> +
> +	vcpu = kvm_get_vcpu(kvm, cpuid);
> +	vgic_update_irq_pending(kvm, vcpu, intid, level);
> +	return 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 61b8d22..e9f4aa6 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -18,5 +18,6 @@
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>  
>  #endif
> -- 
> 2.7.3
> 

Otherwise the split between update/queue looks reasonable here.

Btw., anywhere where I write 'you' in this mail, I mean 'we' and take
partial blame for any bugs here :)

Thanks,
-Christoffer

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

* [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-03-29 21:16     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-29 21:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:29AM +0000, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Provide a vgic_queue_irq() function which decides whether a given
> IRQ needs to be queued to a VCPU's ap_list.
> This should be called whenever an IRQ became pending or got enabled,

becomes pending or enabled,

> either as a result of userspace injection, from in-kernel emulated
> devices like the architected timer or from MMIO accesses to the
> distributor emulation.
> Also provides the necessary functions to allow userland to inject an
> IRQ to a guest.

Since this is the first code that starts using our locking mechanism, we
add some (hopefully) clear documentation of our locking strategy and
requirements along with this patch.

> [Andre: refactor out vgic_queue_irq()]
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h  |   3 +
>  virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   1 +
>  3 files changed, 185 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 659f8b1..f32b284 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -178,6 +178,9 @@ struct vgic_cpu {
>  	struct list_head ap_list_head;
>  };
>  
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level);
> +
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(false)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 8e34916..a95aabc 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -19,8 +19,25 @@
>  
>  #include "vgic.h"
>  
> +#define CREATE_TRACE_POINTS
> +#include "../trace.h"
> +
>  struct vgic_global kvm_vgic_global_state;
>  
> +/*
> + * Locking order is always:
> + *   vgic_cpu->ap_list_lock
> + *     vgic_irq->irq_lock
> + *
> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
> + *
> + * When taking more than one ap_list_lock at the same time, always take the
> + * lowest numbered VCPU's ap_list_lock first, so:
> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
> + */
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid)
>  {
> @@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>  	return NULL;
>  }
> +
> +/**
> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
> + *
> + * @irq:	The irq to route. Must be already locked.
> + *
> + * Based on the current state of the interrupt (enabled, pending,
> + * active, vcpu and target_vcpu), compute the next vcpu this should be
> + * given to. Return NULL if this shouldn't be injected at all.
> + */
> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
> +{
> +	/* If the interrupt is active, it must stay on the current vcpu */
> +	if (irq->active)
> +		return irq->vcpu;

we are not taking a lock here.  What are the locking expectations?  If
the expectarions are that the IRQ is locked when calling this function,
can we have a BIG FAT COMMENT saying that then?

It seems to me that we are somehow expecting irq->active and irq->vcpu
to be in sync, but that's not necessarily the case if the IRQ is not
locked.

> +
> +	/* If enabled and pending, it can migrate to a new one */

I think this comment should be rewritten to:

If the IRQ is not active but enabled and pending, we should direct it to
its configured target VCPU.

> +	if (irq->enabled && irq->pending)
> +		return irq->target_vcpu;
> +
> +	/* Otherwise, it is considered idle */

not sure what idle means here, I suggest something like:

If neither active nor pending and enabled, then this IRQ should not be
queued to any VCPU.

> +	return NULL;
> +}
> +
> +/*
> + * Only valid injection if changing level for level-triggered IRQs or for a
> + * rising edge.
> + */
> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
> +{
> +	switch (irq->config) {
> +	case VGIC_CONFIG_LEVEL:
> +		return irq->line_level != level;
> +	case VGIC_CONFIG_EDGE:
> +		return level;
> +	default:
> +		BUG();

is the default case there for making the compiler happy or can we just
get rid of it?

> +	}
> +}
> +
> +/*
> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
> + * Do the queuing if necessary, taking the right locks in the right order.
> + * Returns true when the IRQ was queued, false otherwise.
> + *
> + * Needs to be entered with the IRQ lock already held, but will return
> + * with all locks dropped.
> + */
> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)

should we name this vgic_try_queue_irq_locked ?

> +{
> +	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);

should we have something like BUG_ON(!spin_is_locked(irq->irq_lock));
here?

Not sure if there's some bug checking here which is only emitted if a
user select CONFIG_CHECK_SOME_LOCKING_THINGS that we could use...?

> +
> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
> +		/*
> +		 * If this IRQ is already on a VCPU's ap_list, then it
> +		 * cannot be moved or modified and there is no more work for
> +		 * us to do.
> +		 *
> +		 * Otherwise, if the irq is not pending and enabled, it does
> +		 * not need to be inserted into an ap_list and there is also
> +		 * no more work for us to do.
> +		 */

is the !vcpu check here not redundant because if you ever get to
evaluating it, then irq->vcpu is null, and pending and enabled are set,
which means the oracle couldn't have returned null, could it?

that would also explain why we don't have to re-check the same
conditions below...

or am I getting this wrong, because you could also have someone
explicitly setting the IRQ to active via trapped MMIO, in which case we
should be able to queue it without it being pending && enabled, which
would indicate that it's the other way around, you should only evaluate
!vcpu and kup the !(pending && enabled) part....?

> +		spin_unlock(&irq->irq_lock);
> +		return false;
> +	}
> +
> +	/*
> +	 * We must unlock the irq lock to take the ap_list_lock where
> +	 * we are going to insert this new pending interrupt.
> +	 */
> +	spin_unlock(&irq->irq_lock);
> +
> +	/* someone can do stuff here, which we re-check below */
> +retry:
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	spin_lock(&irq->irq_lock);
> +
> +	/*
> +	 * Did something change behind our backs?
> +	 *
> +	 * There are two cases:
> +	 * 1) The irq became pending or active behind our backs and/or
> +	 *    the irq->vcpu field was set correspondingly when putting
> +	 *    the irq on an ap_list. Then drop the locks and return.
> +	 * 2) Someone changed the affinity on this irq behind our
> +	 *    backs and we are now holding the wrong ap_list_lock.
> +	 *    Then drop the locks and try the new VCPU.
> +	 */
> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {

here I'm concerned about the active state again.

I feel like something more similar to my initial version of this patch
is what we really want:

       if (irq->vcpu || vcpu != vgic_target_oracle(irq))
           goto real_retry;

and read_retry is then a label at the very top of this function, before
the initial call to vgic_target_oracle()....

> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +		return false;
> +	}
> +
> +	if (irq->target_vcpu != vcpu) {
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +		vcpu = irq->target_vcpu;
> +		goto retry;
> +	}
> +
> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> +	irq->vcpu = vcpu;
> +
> +	spin_unlock(&irq->irq_lock);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +	kvm_vcpu_kick(vcpu);
> +
> +	return true;
> +}
> +
> +static void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +				    u32 intid, bool level)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
> +
> +	trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
> +
> +	BUG_ON(in_interrupt());

I don't remember why we thought it was a good idea to have this BUG_ON()
anymore.  Anyone?

> +
> +	spin_lock(&irq->irq_lock);
> +
> +	if (!vgic_validate_injection(irq, level)) {
> +		/* Nothing to see here, move along... */
> +		spin_unlock(&irq->irq_lock);
> +		return;
> +	}
> +
> +	if (irq->config == VGIC_CONFIG_LEVEL) {
> +		irq->line_level = level;
> +		irq->pending = level || irq->soft_pending;
> +	} else {
> +		irq->pending = true;
> +	}
> +
> +	vgic_queue_irq(kvm, irq);
> +}
> +
> +/**
> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
> + * @kvm:     The VM structure pointer
> + * @cpuid:   The CPU for PPIs
> + * @intid:   The INTID to inject a new state to.
> + *           must not be mapped to a HW interrupt.

stray line here?  I don't understand this bit about 'must not be mapped'
and I think that should be moved to the explanation below with some
rationale, and if important, perhaps guarded with a BUG_ON() ?

> + * @level:   Edge-triggered:  true:  to trigger the interrupt
> + *			      false: to ignore the call
> + *	     Level-sensitive  true:  raise the input signal
> + *			      false: lower the input signal
> + *
> + * The GIC is not concerned with devices being active-LOW or active-HIGH for

We should probably write VGIC here instead of GIC, just to avoid
confusion.

> + * level-sensitive interrupts.  You can think of the level parameter as 1
> + * being HIGH and 0 being LOW and all devices being active-HIGH.
> + */
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level)
> +{
> +	struct kvm_vcpu *vcpu;
> +
> +	vcpu = kvm_get_vcpu(kvm, cpuid);
> +	vgic_update_irq_pending(kvm, vcpu, intid, level);
> +	return 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 61b8d22..e9f4aa6 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -18,5 +18,6 @@
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>  
>  #endif
> -- 
> 2.7.3
> 

Otherwise the split between update/queue looks reasonable here.

Btw., anywhere where I write 'you' in this mail, I mean 'we' and take
partial blame for any bugs here :)

Thanks,
-Christoffer

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

* Re: [RFC PATCH 07/45] KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-30  9:29     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30  9:29 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:30AM +0000, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Introduce vgic-v2.c to contain GICv2 specific functions.
> Add vgic_v2_irq_change_affinity() to change the target VCPU of a
> particular interrupt.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-v2.c | 40 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h    |  2 ++
>  2 files changed, 42 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> new file mode 100644
> index 0000000..0bf6f27
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -0,0 +1,40 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * 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/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct vgic_irq *irq;
> +	int target;
> +
> +	BUG_ON(intid <= VGIC_MAX_PRIVATE);
> +	BUG_ON(dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2);

we can probably get rid of the last BUG_ON here.

> +
> +	irq = vgic_get_irq(kvm, NULL, intid);
> +
> +	spin_lock(&irq->irq_lock);
> +	irq->targets = new_targets;
> +
> +	target = ffs(irq->targets);
> +	target = target ? (target - 1) : 0;
> +	irq->target_vcpu = kvm_get_vcpu(kvm, target);
> +	spin_unlock(&irq->irq_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index e9f4aa6..b2faf00 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -20,4 +20,6 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>  
> +void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
> +
>  #endif
> -- 
> 2.7.3
> 

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

* [RFC PATCH 07/45] KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity
@ 2016-03-30  9:29     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30  9:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:30AM +0000, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Introduce vgic-v2.c to contain GICv2 specific functions.
> Add vgic_v2_irq_change_affinity() to change the target VCPU of a
> particular interrupt.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-v2.c | 40 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h    |  2 ++
>  2 files changed, 42 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> new file mode 100644
> index 0000000..0bf6f27
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -0,0 +1,40 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * 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/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct vgic_irq *irq;
> +	int target;
> +
> +	BUG_ON(intid <= VGIC_MAX_PRIVATE);
> +	BUG_ON(dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2);

we can probably get rid of the last BUG_ON here.

> +
> +	irq = vgic_get_irq(kvm, NULL, intid);
> +
> +	spin_lock(&irq->irq_lock);
> +	irq->targets = new_targets;
> +
> +	target = ffs(irq->targets);
> +	target = target ? (target - 1) : 0;
> +	irq->target_vcpu = kvm_get_vcpu(kvm, target);
> +	spin_unlock(&irq->irq_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index e9f4aa6..b2faf00 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -20,4 +20,6 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>  
> +void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
> +
>  #endif
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-29 13:12   ` Vladimir Murzin
@ 2016-03-30 11:42     ` Vladimir Murzin
  -1 siblings, 0 replies; 276+ messages in thread
From: Vladimir Murzin @ 2016-03-30 11:42 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall, Marc Zyngier, Eric Auger
  Cc: kvmarm, linux-arm-kernel, kvm

On 29/03/16 14:12, Vladimir Murzin wrote:
> Hi Andre,
> 
> On 25/03/16 02:04, Andre Przywara wrote:
>> Please have a look at the series, review it and give the code some
>> serious testing (and possibly debugging). All feedback is appreciated.
> 
> I see that with the new vgic implementation kvmtool starts throwing:
> 
> kvm [1273]: Unable to register VGICv3 redist MMIO regions
> 

It comes from kvm_io_bus_register_dev()

if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
	return -ENOSPC;

with bus->dev_count being 1000

[<ffffffc00009f93c>] kvm_io_bus_register_dev+0x130/0x148
[<ffffffc0000ad274>] kvm_vgic_register_mmio_region+0xac/0xdc
[<ffffffc0000ad4d4>] vgic_register_redist_regions+0xb8/0x158
[<ffffffc0000abb90>] vgic_v3_map_resources+0x5c/0xf0
[<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
[<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
[<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
[<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
[<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
[<ffffffc000085d30>] el0_svc_naked+0x24/0x28

Hope this helps...
Vladimir

> for --cpus 58 and above, where with the old vgic it is quite happy with
> up to 255 cpus.
> 
> Cheers
> Vladimir
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
> 
> 

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-30 11:42     ` Vladimir Murzin
  0 siblings, 0 replies; 276+ messages in thread
From: Vladimir Murzin @ 2016-03-30 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/03/16 14:12, Vladimir Murzin wrote:
> Hi Andre,
> 
> On 25/03/16 02:04, Andre Przywara wrote:
>> Please have a look at the series, review it and give the code some
>> serious testing (and possibly debugging). All feedback is appreciated.
> 
> I see that with the new vgic implementation kvmtool starts throwing:
> 
> kvm [1273]: Unable to register VGICv3 redist MMIO regions
> 

It comes from kvm_io_bus_register_dev()

if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
	return -ENOSPC;

with bus->dev_count being 1000

[<ffffffc00009f93c>] kvm_io_bus_register_dev+0x130/0x148
[<ffffffc0000ad274>] kvm_vgic_register_mmio_region+0xac/0xdc
[<ffffffc0000ad4d4>] vgic_register_redist_regions+0xb8/0x158
[<ffffffc0000abb90>] vgic_v3_map_resources+0x5c/0xf0
[<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
[<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
[<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
[<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
[<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
[<ffffffc000085d30>] el0_svc_naked+0x24/0x28

Hope this helps...
Vladimir

> for --cpus 58 and above, where with the old vgic it is quite happy with
> up to 255 cpus.
> 
> Cheers
> Vladimir
> _______________________________________________
> kvmarm mailing list
> kvmarm at lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
> 
> 

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-30 11:42     ` Vladimir Murzin
@ 2016-03-30 11:52       ` Vladimir Murzin
  -1 siblings, 0 replies; 276+ messages in thread
From: Vladimir Murzin @ 2016-03-30 11:52 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall, Marc Zyngier, Eric Auger
  Cc: kvmarm, linux-arm-kernel, kvm

On 30/03/16 12:42, Vladimir Murzin wrote:
> On 29/03/16 14:12, Vladimir Murzin wrote:
>> Hi Andre,
>>
>> On 25/03/16 02:04, Andre Przywara wrote:
>>> Please have a look at the series, review it and give the code some
>>> serious testing (and possibly debugging). All feedback is appreciated.
>>
>> I see that with the new vgic implementation kvmtool starts throwing:
>>
>> kvm [1273]: Unable to register VGICv3 redist MMIO regions
>>
> 
> It comes from kvm_io_bus_register_dev()
> 
> if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
> 	return -ENOSPC;
> 
> with bus->dev_count being 1000
> 
> [<ffffffc00009f93c>] kvm_io_bus_register_dev+0x130/0x148
> [<ffffffc0000ad274>] kvm_vgic_register_mmio_region+0xac/0xdc
> [<ffffffc0000ad4d4>] vgic_register_redist_regions+0xb8/0x158
> [<ffffffc0000abb90>] vgic_v3_map_resources+0x5c/0xf0
> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
> 

and one more thing I've forgotten to mention... something odd happens on
destroy path

INFO: task kvm-vcpu-0:1123 blocked for more than 120 seconds.
      Tainted: G        W       4.5.0-rc6+ #432
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
kvm-vcpu-0      D ffffffc000086bcc     0  1123   1114 0x00000008
Call trace:
[<ffffffc000086bcc>] __switch_to+0x90/0xa4
[<ffffffc0006c4390>] __schedule+0x188/0x59c
[<ffffffc0006c47e0>] schedule+0x3c/0xa0
[<ffffffc0006c4bf4>] schedule_preempt_disabled+0x20/0x38
[<ffffffc0006c618c>] __mutex_lock_slowpath+0xc4/0x148
[<ffffffc0006c6254>] mutex_lock+0x44/0x5c
[<ffffffc0000aacb8>] kvm_vgic_destroy+0x20/0xb0
[<ffffffc0000abbdc>] vgic_v3_map_resources+0xa8/0xf0
[<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
[<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
[<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
[<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
[<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
[<ffffffc000085d30>] el0_svc_naked+0x24/0x28

Vladimir

> Hope this helps...
> Vladimir
> 
>> for --cpus 58 and above, where with the old vgic it is quite happy with
>> up to 255 cpus.
>>
>> Cheers
>> Vladimir
>> _______________________________________________
>> kvmarm mailing list
>> kvmarm@lists.cs.columbia.edu
>> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
>>
>>
> 
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
> 
> 

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-30 11:52       ` Vladimir Murzin
  0 siblings, 0 replies; 276+ messages in thread
From: Vladimir Murzin @ 2016-03-30 11:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 30/03/16 12:42, Vladimir Murzin wrote:
> On 29/03/16 14:12, Vladimir Murzin wrote:
>> Hi Andre,
>>
>> On 25/03/16 02:04, Andre Przywara wrote:
>>> Please have a look at the series, review it and give the code some
>>> serious testing (and possibly debugging). All feedback is appreciated.
>>
>> I see that with the new vgic implementation kvmtool starts throwing:
>>
>> kvm [1273]: Unable to register VGICv3 redist MMIO regions
>>
> 
> It comes from kvm_io_bus_register_dev()
> 
> if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
> 	return -ENOSPC;
> 
> with bus->dev_count being 1000
> 
> [<ffffffc00009f93c>] kvm_io_bus_register_dev+0x130/0x148
> [<ffffffc0000ad274>] kvm_vgic_register_mmio_region+0xac/0xdc
> [<ffffffc0000ad4d4>] vgic_register_redist_regions+0xb8/0x158
> [<ffffffc0000abb90>] vgic_v3_map_resources+0x5c/0xf0
> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
> 

and one more thing I've forgotten to mention... something odd happens on
destroy path

INFO: task kvm-vcpu-0:1123 blocked for more than 120 seconds.
      Tainted: G        W       4.5.0-rc6+ #432
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
kvm-vcpu-0      D ffffffc000086bcc     0  1123   1114 0x00000008
Call trace:
[<ffffffc000086bcc>] __switch_to+0x90/0xa4
[<ffffffc0006c4390>] __schedule+0x188/0x59c
[<ffffffc0006c47e0>] schedule+0x3c/0xa0
[<ffffffc0006c4bf4>] schedule_preempt_disabled+0x20/0x38
[<ffffffc0006c618c>] __mutex_lock_slowpath+0xc4/0x148
[<ffffffc0006c6254>] mutex_lock+0x44/0x5c
[<ffffffc0000aacb8>] kvm_vgic_destroy+0x20/0xb0
[<ffffffc0000abbdc>] vgic_v3_map_resources+0xa8/0xf0
[<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
[<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
[<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
[<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
[<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
[<ffffffc000085d30>] el0_svc_naked+0x24/0x28

Vladimir

> Hope this helps...
> Vladimir
> 
>> for --cpus 58 and above, where with the old vgic it is quite happy with
>> up to 255 cpus.
>>
>> Cheers
>> Vladimir
>> _______________________________________________
>> kvmarm mailing list
>> kvmarm at lists.cs.columbia.edu
>> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
>>
>>
> 
> _______________________________________________
> kvmarm mailing list
> kvmarm at lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
> 
> 

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-30 11:42     ` Vladimir Murzin
@ 2016-03-30 12:07       ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2016-03-30 12:07 UTC (permalink / raw)
  To: Vladimir Murzin, Andre Przywara, Christoffer Dall, Eric Auger
  Cc: kvmarm, linux-arm-kernel, kvm

On 30/03/16 12:42, Vladimir Murzin wrote:
> On 29/03/16 14:12, Vladimir Murzin wrote:
>> Hi Andre,
>>
>> On 25/03/16 02:04, Andre Przywara wrote:
>>> Please have a look at the series, review it and give the code some
>>> serious testing (and possibly debugging). All feedback is appreciated.
>>
>> I see that with the new vgic implementation kvmtool starts throwing:
>>
>> kvm [1273]: Unable to register VGICv3 redist MMIO regions
>>
> 
> It comes from kvm_io_bus_register_dev()
> 
> if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
> 	return -ENOSPC;
> 
> with bus->dev_count being 1000

Ouch. That's a consequence of having one "device" per actual register
set, I believe. So either we bump this limit up by a factor 10 (at
least), or we switch back to the old way of handling access to the GIC
regions (big "catch-all", and further demuxing).

Thoughts?

Thanks,

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

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-30 12:07       ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2016-03-30 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

On 30/03/16 12:42, Vladimir Murzin wrote:
> On 29/03/16 14:12, Vladimir Murzin wrote:
>> Hi Andre,
>>
>> On 25/03/16 02:04, Andre Przywara wrote:
>>> Please have a look at the series, review it and give the code some
>>> serious testing (and possibly debugging). All feedback is appreciated.
>>
>> I see that with the new vgic implementation kvmtool starts throwing:
>>
>> kvm [1273]: Unable to register VGICv3 redist MMIO regions
>>
> 
> It comes from kvm_io_bus_register_dev()
> 
> if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
> 	return -ENOSPC;
> 
> with bus->dev_count being 1000

Ouch. That's a consequence of having one "device" per actual register
set, I believe. So either we bump this limit up by a factor 10 (at
least), or we switch back to the old way of handling access to the GIC
regions (big "catch-all", and further demuxing).

Thoughts?

Thanks,

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

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

* Re: [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-30 13:53     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30 13:53 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the functionality for syncing IRQs between our emulation
> and the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.

I thought we agreed to split this up in a generic part and then GICv2
and GICv3 parts following, but ok, I'll look through this code, but I
strongly suggest splitting it up for the next posting.

> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h     |   4 +
>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h    |   4 +
>  4 files changed, 373 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index f32b284..986f23f 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>  
> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 0bf6f27..1cec423 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -14,11 +14,172 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> +#include <linux/irqchip/arm-gic.h>
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
>  
>  #include "vgic.h"
>  
> +/*
> + * Call this function to convert a u64 value to an unsigned long * bitmask
> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> + *
> + * Warning: Calling this function may modify *val.
> + */
> +static unsigned long *u64_to_bitmask(u64 *val)
> +{
> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> +	*val = (*val >> 32) | (*val << 32);
> +#endif
> +	return (unsigned long *)val;
> +}
> +
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> +		u64 eisr = cpuif->vgic_eisr;
> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> +		int lr;
> +
> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> +			struct vgic_irq *irq;
> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> +
> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */

we just had a warning above if the LR state was set, so how do we
expect this to be modified in the mean time?

The following line caters for the famous hardware race, right?  If so, I think it deserved a comment:

/*
 * The hardware doesn't guarantee that the LR's bit is set in the ELRSR
 * despite the virtual interrupt being EOIed and generating a
 * maintenance interrupt.  Force the bit to be set.
 */

> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +	}
> +
> +	/* check and disable underflow maintenance IRQ */

s/check and d/D/

> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;

I think the above should be moved to fold_lr_state

> +
> +	/*
> +	 * In the next iterations of the vcpu loop, if we sync the
> +	 * vgic state after flushing it, but before entering the guest
> +	 * (this happens for pending signals and vmid rollovers), then
> +	 * make sure we don't pick up any old maintenance interrupts
> +	 * here.
> +	 */
> +	cpuif->vgic_eisr = 0;
> +}
> +
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> +}
> +
> +/*
> + * transfer the content of the LRs back into the corresponding ap_list:
> + * - active bit is transferred as is
> + * - pending bit is
> + *   - transferred as is in case of edge sensitive IRQs
> + *   - set to the line-level (resample time) for level sensitive IRQs
> + */
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int lr;
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u32 val = cpuif->vgic_lr[lr];
> +		u32 intid = val & GICH_LR_VIRTUALID;
> +		struct vgic_irq *irq;
> +
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & GICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (intid < VGIC_NR_SGIS) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;

Are we happy with relying on all the remaining bits being 0 here or
should we define a proper CPUID mask?

> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level IRQs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & GICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/*
> + * Populates the particular LR with the state of a given IRQ:
> + * - for an edge sensitive IRQ the pending state is reset in the struct

s/reset/cleared/
s/the struct/the vgic_irq struct/

> + * - for a level sensitive IRQ the pending state value is unchanged;
> + *   it will be resampled on deactivation

s/
it will be resampled on deactivation/
it is dictated directly by the input level/

> + *
> + * If irq is not NULL, the irq_lock must be hold already by the caller.

s/hold/held/

> + * If irq is NULL, the respective LR gets cleared.

If @irq describes an SGI with multiple sources, we choose the
lowest-numbered source VCPU and clear that bit in the source bitmap.

> + */
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 val;
> +
> +	if (!irq) {
> +		val = 0;
> +		goto out;
> +	}

I'm not convinced about keeping this functionality in this function.

Wouldn't it be much more clear to have vgic_clear_lr() as a separate
function?

> +
> +	val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= GICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (irq->intid < VGIC_NR_SGIS) {
> +			u32 src = ffs(irq->source);

can't you do src = __ffs(irq->source) here to avoid the (src - 1) below?

> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= GICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= GICH_LR_HW;
> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= GICH_LR_EOI;
> +	}
> +
> +out:
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
> +}
> +
>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 29c753e..90a85bf 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>  	return 0;
>  }
> +
> +/**
> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> + *
> + * @vcpu: The VCPU pointer
> + *
> + * Go over the list of "interesting" interrupts, and prune those that we
> + * won't have to consider in the near future.
> + */
> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq, *tmp;
> +
> +retry:
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		BUG_ON(vcpu != irq->vcpu);
> +
> +		target_vcpu = vgic_target_oracle(irq);
> +
> +		if (!target_vcpu) {
> +			/*
> +			 * We don't need to process this interrupt any
> +			 * further, move it off the list.
> +			 */
> +			list_del_init(&irq->ap_list);

why list_del_init and not list_del here?  do we ever do list_empty() on
the &irq->ap_list ?

> +			irq->vcpu = NULL;
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		if (target_vcpu == vcpu) {
> +			/* We're on the right CPU */
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		/* This interrupt looks like it has to be migrated. */
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +		/*
> +		 * Ensure locking order by always locking the smallest
> +		 * ID first.
> +		 */
> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> +			vcpuA = vcpu;
> +			vcpuB = target_vcpu;
> +		} else {
> +			vcpuA = target_vcpu;
> +			vcpuB = vcpu;
> +		}
> +
> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * If the affinity has been preserved, move the
> +		 * interrupt around. Otherwise, it means things have
> +		 * changed while the interrupt was unlocked, and we
> +		 * need to replay this.
> +		 *
> +		 * In all cases, we cannot trust the list not to have
> +		 * changed, so we restart from the beginning.
> +		 */
> +		if (target_vcpu == vgic_target_oracle(irq)) {
> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> +
> +			list_del_init(&irq->ap_list);

again, why list_del_init and not just list_del ?

> +			irq->vcpu = target_vcpu;
> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		goto retry;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +}
> +
> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_process_maintenance(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_fold_lr_state(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +/*
> + * Requires the ap_lock to be held.
> + * If irq is not NULL, requires the IRQ lock to be held as well.
> + * If irq is NULL, the list register gets cleared.
> + */
> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> +				    struct vgic_irq *irq, int lr)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_populate_lr(vcpu, irq, lr);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_set_underflow(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		/* GICv2 SGIs can count for more than one... */
> +		if (irq->intid < VGIC_NR_SGIS && irq->source)

how can we have an SGI on an AP list without the irq->source field set?

Is the irq->source check to cater for GICv3?

> +			count += hweight8(irq->source);
> +		else
> +			count++;
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return count;

this does feel like an awful lot of code on each entry.  I'm wondering
if we should have a count on each vgic_cpu containing the length of the
AP list which is then adjusted via the queue and removal functions?

> +}
> +
> +/* requires the vcpu ap_lock to be held */

s/ap_lock/ap_list_lock/

> +static void vgic_populate_lrs(struct kvm_vcpu *vcpu)

I'm not in love with the fact that we have two separate functions named:

  vgic_populate_lrs  and
  vgic_populate_lr

perhaps this could be changed to 'vgic_flush_ap_list' ?

> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
> +		    irq->intid < VGIC_NR_SGIS) {

I wonder if a lot of this code would be more readable if we added and
used the following primitives:
vgic_irq_is_sgi()
vgic_irq_is_ppi()
vgic_irq_is_spi()

> +			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
> +				vgic_populate_lr(vcpu, irq, count++);
> +		} else {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		}

this stuff about the SGIs is really dense, so I'm wondering if it's more
clean to make it even more dense and rewrite the whole if-statement to:

	do {
		vgic_populate(vcpu, irq, count++);
	} while (irq->source && count < vgic.nr_lr);

(btw. I believe all these places referencing the nr_lr in the vgic_cpu
struct could use the global state structure instead).

> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == vcpu->arch.vgic_cpu.nr_lr)
> +			break;
> +	}
> +
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
> +		vgic_populate_lr(vcpu, NULL, count);

should we not change this to adhere to the optimizations Marc
implemented for the current VGIC (i.e. clear the LRs on sync+init, and
only write what you need here)?

> +}
> +
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_fold_lr_state(vcpu);
> +	vgic_prune_ap_list(vcpu);
> +}
> +
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	vgic_populate_lrs(vcpu);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index b2faf00..95ef3cf 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -21,5 +21,9 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>  
>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  
>  #endif
> -- 
> 2.7.3
> 

Thanks,
-Christoffer

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

* [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
@ 2016-03-30 13:53     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the functionality for syncing IRQs between our emulation
> and the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.

I thought we agreed to split this up in a generic part and then GICv2
and GICv3 parts following, but ok, I'll look through this code, but I
strongly suggest splitting it up for the next posting.

> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h     |   4 +
>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h    |   4 +
>  4 files changed, 373 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index f32b284..986f23f 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>  
> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 0bf6f27..1cec423 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -14,11 +14,172 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> +#include <linux/irqchip/arm-gic.h>
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
>  
>  #include "vgic.h"
>  
> +/*
> + * Call this function to convert a u64 value to an unsigned long * bitmask
> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> + *
> + * Warning: Calling this function may modify *val.
> + */
> +static unsigned long *u64_to_bitmask(u64 *val)
> +{
> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> +	*val = (*val >> 32) | (*val << 32);
> +#endif
> +	return (unsigned long *)val;
> +}
> +
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> +		u64 eisr = cpuif->vgic_eisr;
> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> +		int lr;
> +
> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> +			struct vgic_irq *irq;
> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> +
> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */

we just had a warning above if the LR state was set, so how do we
expect this to be modified in the mean time?

The following line caters for the famous hardware race, right?  If so, I think it deserved a comment:

/*
 * The hardware doesn't guarantee that the LR's bit is set in the ELRSR
 * despite the virtual interrupt being EOIed and generating a
 * maintenance interrupt.  Force the bit to be set.
 */

> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +	}
> +
> +	/* check and disable underflow maintenance IRQ */

s/check and d/D/

> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;

I think the above should be moved to fold_lr_state

> +
> +	/*
> +	 * In the next iterations of the vcpu loop, if we sync the
> +	 * vgic state after flushing it, but before entering the guest
> +	 * (this happens for pending signals and vmid rollovers), then
> +	 * make sure we don't pick up any old maintenance interrupts
> +	 * here.
> +	 */
> +	cpuif->vgic_eisr = 0;
> +}
> +
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> +}
> +
> +/*
> + * transfer the content of the LRs back into the corresponding ap_list:
> + * - active bit is transferred as is
> + * - pending bit is
> + *   - transferred as is in case of edge sensitive IRQs
> + *   - set to the line-level (resample time) for level sensitive IRQs
> + */
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int lr;
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u32 val = cpuif->vgic_lr[lr];
> +		u32 intid = val & GICH_LR_VIRTUALID;
> +		struct vgic_irq *irq;
> +
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & GICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (intid < VGIC_NR_SGIS) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;

Are we happy with relying on all the remaining bits being 0 here or
should we define a proper CPUID mask?

> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level IRQs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & GICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/*
> + * Populates the particular LR with the state of a given IRQ:
> + * - for an edge sensitive IRQ the pending state is reset in the struct

s/reset/cleared/
s/the struct/the vgic_irq struct/

> + * - for a level sensitive IRQ the pending state value is unchanged;
> + *   it will be resampled on deactivation

s/
it will be resampled on deactivation/
it is dictated directly by the input level/

> + *
> + * If irq is not NULL, the irq_lock must be hold already by the caller.

s/hold/held/

> + * If irq is NULL, the respective LR gets cleared.

If @irq describes an SGI with multiple sources, we choose the
lowest-numbered source VCPU and clear that bit in the source bitmap.

> + */
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 val;
> +
> +	if (!irq) {
> +		val = 0;
> +		goto out;
> +	}

I'm not convinced about keeping this functionality in this function.

Wouldn't it be much more clear to have vgic_clear_lr() as a separate
function?

> +
> +	val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= GICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (irq->intid < VGIC_NR_SGIS) {
> +			u32 src = ffs(irq->source);

can't you do src = __ffs(irq->source) here to avoid the (src - 1) below?

> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= GICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= GICH_LR_HW;
> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= GICH_LR_EOI;
> +	}
> +
> +out:
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
> +}
> +
>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 29c753e..90a85bf 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>  	return 0;
>  }
> +
> +/**
> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> + *
> + * @vcpu: The VCPU pointer
> + *
> + * Go over the list of "interesting" interrupts, and prune those that we
> + * won't have to consider in the near future.
> + */
> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq, *tmp;
> +
> +retry:
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		BUG_ON(vcpu != irq->vcpu);
> +
> +		target_vcpu = vgic_target_oracle(irq);
> +
> +		if (!target_vcpu) {
> +			/*
> +			 * We don't need to process this interrupt any
> +			 * further, move it off the list.
> +			 */
> +			list_del_init(&irq->ap_list);

why list_del_init and not list_del here?  do we ever do list_empty() on
the &irq->ap_list ?

> +			irq->vcpu = NULL;
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		if (target_vcpu == vcpu) {
> +			/* We're on the right CPU */
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		/* This interrupt looks like it has to be migrated. */
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +		/*
> +		 * Ensure locking order by always locking the smallest
> +		 * ID first.
> +		 */
> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> +			vcpuA = vcpu;
> +			vcpuB = target_vcpu;
> +		} else {
> +			vcpuA = target_vcpu;
> +			vcpuB = vcpu;
> +		}
> +
> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * If the affinity has been preserved, move the
> +		 * interrupt around. Otherwise, it means things have
> +		 * changed while the interrupt was unlocked, and we
> +		 * need to replay this.
> +		 *
> +		 * In all cases, we cannot trust the list not to have
> +		 * changed, so we restart from the beginning.
> +		 */
> +		if (target_vcpu == vgic_target_oracle(irq)) {
> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> +
> +			list_del_init(&irq->ap_list);

again, why list_del_init and not just list_del ?

> +			irq->vcpu = target_vcpu;
> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		goto retry;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +}
> +
> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_process_maintenance(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_fold_lr_state(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +/*
> + * Requires the ap_lock to be held.
> + * If irq is not NULL, requires the IRQ lock to be held as well.
> + * If irq is NULL, the list register gets cleared.
> + */
> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> +				    struct vgic_irq *irq, int lr)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_populate_lr(vcpu, irq, lr);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_set_underflow(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		/* GICv2 SGIs can count for more than one... */
> +		if (irq->intid < VGIC_NR_SGIS && irq->source)

how can we have an SGI on an AP list without the irq->source field set?

Is the irq->source check to cater for GICv3?

> +			count += hweight8(irq->source);
> +		else
> +			count++;
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return count;

this does feel like an awful lot of code on each entry.  I'm wondering
if we should have a count on each vgic_cpu containing the length of the
AP list which is then adjusted via the queue and removal functions?

> +}
> +
> +/* requires the vcpu ap_lock to be held */

s/ap_lock/ap_list_lock/

> +static void vgic_populate_lrs(struct kvm_vcpu *vcpu)

I'm not in love with the fact that we have two separate functions named:

  vgic_populate_lrs  and
  vgic_populate_lr

perhaps this could be changed to 'vgic_flush_ap_list' ?

> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
> +		    irq->intid < VGIC_NR_SGIS) {

I wonder if a lot of this code would be more readable if we added and
used the following primitives:
vgic_irq_is_sgi()
vgic_irq_is_ppi()
vgic_irq_is_spi()

> +			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
> +				vgic_populate_lr(vcpu, irq, count++);
> +		} else {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		}

this stuff about the SGIs is really dense, so I'm wondering if it's more
clean to make it even more dense and rewrite the whole if-statement to:

	do {
		vgic_populate(vcpu, irq, count++);
	} while (irq->source && count < vgic.nr_lr);

(btw. I believe all these places referencing the nr_lr in the vgic_cpu
struct could use the global state structure instead).

> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == vcpu->arch.vgic_cpu.nr_lr)
> +			break;
> +	}
> +
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
> +		vgic_populate_lr(vcpu, NULL, count);

should we not change this to adhere to the optimizations Marc
implemented for the current VGIC (i.e. clear the LRs on sync+init, and
only write what you need here)?

> +}
> +
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_fold_lr_state(vcpu);
> +	vgic_prune_ap_list(vcpu);
> +}
> +
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	vgic_populate_lrs(vcpu);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index b2faf00..95ef3cf 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -21,5 +21,9 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>  
>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  
>  #endif
> -- 
> 2.7.3
> 

Thanks,
-Christoffer

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-30 11:52       ` Vladimir Murzin
@ 2016-03-30 13:56         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30 13:56 UTC (permalink / raw)
  To: Vladimir Murzin
  Cc: Andre Przywara, Marc Zyngier, Eric Auger, kvmarm, linux-arm-kernel, kvm

Hi Vladimir,

On Wed, Mar 30, 2016 at 12:52:27PM +0100, Vladimir Murzin wrote:
> On 30/03/16 12:42, Vladimir Murzin wrote:
> > On 29/03/16 14:12, Vladimir Murzin wrote:
> >> Hi Andre,
> >>
> >> On 25/03/16 02:04, Andre Przywara wrote:
> >>> Please have a look at the series, review it and give the code some
> >>> serious testing (and possibly debugging). All feedback is appreciated.
> >>
> >> I see that with the new vgic implementation kvmtool starts throwing:
> >>
> >> kvm [1273]: Unable to register VGICv3 redist MMIO regions
> >>
> > 
> > It comes from kvm_io_bus_register_dev()
> > 
> > if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
> > 	return -ENOSPC;
> > 
> > with bus->dev_count being 1000
> > 
> > [<ffffffc00009f93c>] kvm_io_bus_register_dev+0x130/0x148
> > [<ffffffc0000ad274>] kvm_vgic_register_mmio_region+0xac/0xdc
> > [<ffffffc0000ad4d4>] vgic_register_redist_regions+0xb8/0x158
> > [<ffffffc0000abb90>] vgic_v3_map_resources+0x5c/0xf0
> > [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
> > [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
> > [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
> > [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
> > [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
> > [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
> > 
> 
> and one more thing I've forgotten to mention... something odd happens on
> destroy path
> 
> INFO: task kvm-vcpu-0:1123 blocked for more than 120 seconds.
>       Tainted: G        W       4.5.0-rc6+ #432
> "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> kvm-vcpu-0      D ffffffc000086bcc     0  1123   1114 0x00000008
> Call trace:
> [<ffffffc000086bcc>] __switch_to+0x90/0xa4
> [<ffffffc0006c4390>] __schedule+0x188/0x59c
> [<ffffffc0006c47e0>] schedule+0x3c/0xa0
> [<ffffffc0006c4bf4>] schedule_preempt_disabled+0x20/0x38
> [<ffffffc0006c618c>] __mutex_lock_slowpath+0xc4/0x148
> [<ffffffc0006c6254>] mutex_lock+0x44/0x5c
> [<ffffffc0000aacb8>] kvm_vgic_destroy+0x20/0xb0
> [<ffffffc0000abbdc>] vgic_v3_map_resources+0xa8/0xf0
> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
> 

Is this also with many many VCPUs or in general?

Thanks,
-Christoffer

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-30 13:56         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30 13:56 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Vladimir,

On Wed, Mar 30, 2016 at 12:52:27PM +0100, Vladimir Murzin wrote:
> On 30/03/16 12:42, Vladimir Murzin wrote:
> > On 29/03/16 14:12, Vladimir Murzin wrote:
> >> Hi Andre,
> >>
> >> On 25/03/16 02:04, Andre Przywara wrote:
> >>> Please have a look at the series, review it and give the code some
> >>> serious testing (and possibly debugging). All feedback is appreciated.
> >>
> >> I see that with the new vgic implementation kvmtool starts throwing:
> >>
> >> kvm [1273]: Unable to register VGICv3 redist MMIO regions
> >>
> > 
> > It comes from kvm_io_bus_register_dev()
> > 
> > if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
> > 	return -ENOSPC;
> > 
> > with bus->dev_count being 1000
> > 
> > [<ffffffc00009f93c>] kvm_io_bus_register_dev+0x130/0x148
> > [<ffffffc0000ad274>] kvm_vgic_register_mmio_region+0xac/0xdc
> > [<ffffffc0000ad4d4>] vgic_register_redist_regions+0xb8/0x158
> > [<ffffffc0000abb90>] vgic_v3_map_resources+0x5c/0xf0
> > [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
> > [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
> > [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
> > [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
> > [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
> > [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
> > 
> 
> and one more thing I've forgotten to mention... something odd happens on
> destroy path
> 
> INFO: task kvm-vcpu-0:1123 blocked for more than 120 seconds.
>       Tainted: G        W       4.5.0-rc6+ #432
> "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> kvm-vcpu-0      D ffffffc000086bcc     0  1123   1114 0x00000008
> Call trace:
> [<ffffffc000086bcc>] __switch_to+0x90/0xa4
> [<ffffffc0006c4390>] __schedule+0x188/0x59c
> [<ffffffc0006c47e0>] schedule+0x3c/0xa0
> [<ffffffc0006c4bf4>] schedule_preempt_disabled+0x20/0x38
> [<ffffffc0006c618c>] __mutex_lock_slowpath+0xc4/0x148
> [<ffffffc0006c6254>] mutex_lock+0x44/0x5c
> [<ffffffc0000aacb8>] kvm_vgic_destroy+0x20/0xb0
> [<ffffffc0000abbdc>] vgic_v3_map_resources+0xa8/0xf0
> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
> 

Is this also with many many VCPUs or in general?

Thanks,
-Christoffer

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-30 13:56         ` Christoffer Dall
@ 2016-03-30 14:13           ` Vladimir Murzin
  -1 siblings, 0 replies; 276+ messages in thread
From: Vladimir Murzin @ 2016-03-30 14:13 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andre Przywara, Marc Zyngier, Eric Auger, kvmarm, linux-arm-kernel, kvm

On 30/03/16 14:56, Christoffer Dall wrote:
> Hi Vladimir,
> 
> On Wed, Mar 30, 2016 at 12:52:27PM +0100, Vladimir Murzin wrote:
>> On 30/03/16 12:42, Vladimir Murzin wrote:
>>> On 29/03/16 14:12, Vladimir Murzin wrote:
>>>> Hi Andre,
>>>>
>>>> On 25/03/16 02:04, Andre Przywara wrote:
>>>>> Please have a look at the series, review it and give the code some
>>>>> serious testing (and possibly debugging). All feedback is appreciated.
>>>>
>>>> I see that with the new vgic implementation kvmtool starts throwing:
>>>>
>>>> kvm [1273]: Unable to register VGICv3 redist MMIO regions
>>>>
>>>
>>> It comes from kvm_io_bus_register_dev()
>>>
>>> if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
>>> 	return -ENOSPC;
>>>
>>> with bus->dev_count being 1000
>>>
>>> [<ffffffc00009f93c>] kvm_io_bus_register_dev+0x130/0x148
>>> [<ffffffc0000ad274>] kvm_vgic_register_mmio_region+0xac/0xdc
>>> [<ffffffc0000ad4d4>] vgic_register_redist_regions+0xb8/0x158
>>> [<ffffffc0000abb90>] vgic_v3_map_resources+0x5c/0xf0
>>> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
>>> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
>>> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
>>> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
>>> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
>>> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
>>>
>>
>> and one more thing I've forgotten to mention... something odd happens on
>> destroy path
>>
>> INFO: task kvm-vcpu-0:1123 blocked for more than 120 seconds.
>>       Tainted: G        W       4.5.0-rc6+ #432
>> "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
>> kvm-vcpu-0      D ffffffc000086bcc     0  1123   1114 0x00000008
>> Call trace:
>> [<ffffffc000086bcc>] __switch_to+0x90/0xa4
>> [<ffffffc0006c4390>] __schedule+0x188/0x59c
>> [<ffffffc0006c47e0>] schedule+0x3c/0xa0
>> [<ffffffc0006c4bf4>] schedule_preempt_disabled+0x20/0x38
>> [<ffffffc0006c618c>] __mutex_lock_slowpath+0xc4/0x148
>> [<ffffffc0006c6254>] mutex_lock+0x44/0x5c
>> [<ffffffc0000aacb8>] kvm_vgic_destroy+0x20/0xb0
>> [<ffffffc0000abbdc>] vgic_v3_map_resources+0xa8/0xf0
>> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
>> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
>> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
>> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
>> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
>> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
>>
> 
> Is this also with many many VCPUs or in general?
> 

It's seen with many many VCPUs. Basically, I see

kvm [1273]: Unable to register VGICv3 redist MMIO regions

and then (if I'm patient enough) I see that backtrace. So the flow looks
like:

el0_svc_naked
...
vgic_v3_map_resources
   vgic_register_redist_regions
       kvm_vgic_register_mmio_region
           kvm_io_bus_register_dev	// return -ENOSPC
   kvm_vgic_destroy
       mutex_lock

Cheers
Vladimir

> Thanks,
> -Christoffer
> 
> 


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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-30 14:13           ` Vladimir Murzin
  0 siblings, 0 replies; 276+ messages in thread
From: Vladimir Murzin @ 2016-03-30 14:13 UTC (permalink / raw)
  To: linux-arm-kernel

On 30/03/16 14:56, Christoffer Dall wrote:
> Hi Vladimir,
> 
> On Wed, Mar 30, 2016 at 12:52:27PM +0100, Vladimir Murzin wrote:
>> On 30/03/16 12:42, Vladimir Murzin wrote:
>>> On 29/03/16 14:12, Vladimir Murzin wrote:
>>>> Hi Andre,
>>>>
>>>> On 25/03/16 02:04, Andre Przywara wrote:
>>>>> Please have a look at the series, review it and give the code some
>>>>> serious testing (and possibly debugging). All feedback is appreciated.
>>>>
>>>> I see that with the new vgic implementation kvmtool starts throwing:
>>>>
>>>> kvm [1273]: Unable to register VGICv3 redist MMIO regions
>>>>
>>>
>>> It comes from kvm_io_bus_register_dev()
>>>
>>> if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
>>> 	return -ENOSPC;
>>>
>>> with bus->dev_count being 1000
>>>
>>> [<ffffffc00009f93c>] kvm_io_bus_register_dev+0x130/0x148
>>> [<ffffffc0000ad274>] kvm_vgic_register_mmio_region+0xac/0xdc
>>> [<ffffffc0000ad4d4>] vgic_register_redist_regions+0xb8/0x158
>>> [<ffffffc0000abb90>] vgic_v3_map_resources+0x5c/0xf0
>>> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
>>> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
>>> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
>>> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
>>> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
>>> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
>>>
>>
>> and one more thing I've forgotten to mention... something odd happens on
>> destroy path
>>
>> INFO: task kvm-vcpu-0:1123 blocked for more than 120 seconds.
>>       Tainted: G        W       4.5.0-rc6+ #432
>> "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
>> kvm-vcpu-0      D ffffffc000086bcc     0  1123   1114 0x00000008
>> Call trace:
>> [<ffffffc000086bcc>] __switch_to+0x90/0xa4
>> [<ffffffc0006c4390>] __schedule+0x188/0x59c
>> [<ffffffc0006c47e0>] schedule+0x3c/0xa0
>> [<ffffffc0006c4bf4>] schedule_preempt_disabled+0x20/0x38
>> [<ffffffc0006c618c>] __mutex_lock_slowpath+0xc4/0x148
>> [<ffffffc0006c6254>] mutex_lock+0x44/0x5c
>> [<ffffffc0000aacb8>] kvm_vgic_destroy+0x20/0xb0
>> [<ffffffc0000abbdc>] vgic_v3_map_resources+0xa8/0xf0
>> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
>> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
>> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
>> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
>> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
>> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
>>
> 
> Is this also with many many VCPUs or in general?
> 

It's seen with many many VCPUs. Basically, I see

kvm [1273]: Unable to register VGICv3 redist MMIO regions

and then (if I'm patient enough) I see that backtrace. So the flow looks
like:

el0_svc_naked
...
vgic_v3_map_resources
   vgic_register_redist_regions
       kvm_vgic_register_mmio_region
           kvm_io_bus_register_dev	// return -ENOSPC
   kvm_vgic_destroy
       mutex_lock

Cheers
Vladimir

> Thanks,
> -Christoffer
> 
> 

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-30 14:13           ` Vladimir Murzin
@ 2016-03-30 19:53             ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30 19:53 UTC (permalink / raw)
  To: Vladimir Murzin
  Cc: Andre Przywara, Marc Zyngier, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Wed, Mar 30, 2016 at 03:13:20PM +0100, Vladimir Murzin wrote:
> On 30/03/16 14:56, Christoffer Dall wrote:
> > Hi Vladimir,
> > 
> > On Wed, Mar 30, 2016 at 12:52:27PM +0100, Vladimir Murzin wrote:
> >> On 30/03/16 12:42, Vladimir Murzin wrote:
> >>> On 29/03/16 14:12, Vladimir Murzin wrote:
> >>>> Hi Andre,
> >>>>
> >>>> On 25/03/16 02:04, Andre Przywara wrote:
> >>>>> Please have a look at the series, review it and give the code some
> >>>>> serious testing (and possibly debugging). All feedback is appreciated.
> >>>>
> >>>> I see that with the new vgic implementation kvmtool starts throwing:
> >>>>
> >>>> kvm [1273]: Unable to register VGICv3 redist MMIO regions
> >>>>
> >>>
> >>> It comes from kvm_io_bus_register_dev()
> >>>
> >>> if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
> >>> 	return -ENOSPC;
> >>>
> >>> with bus->dev_count being 1000
> >>>
> >>> [<ffffffc00009f93c>] kvm_io_bus_register_dev+0x130/0x148
> >>> [<ffffffc0000ad274>] kvm_vgic_register_mmio_region+0xac/0xdc
> >>> [<ffffffc0000ad4d4>] vgic_register_redist_regions+0xb8/0x158
> >>> [<ffffffc0000abb90>] vgic_v3_map_resources+0x5c/0xf0
> >>> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
> >>> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
> >>> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
> >>> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
> >>> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
> >>> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
> >>>
> >>
> >> and one more thing I've forgotten to mention... something odd happens on
> >> destroy path
> >>
> >> INFO: task kvm-vcpu-0:1123 blocked for more than 120 seconds.
> >>       Tainted: G        W       4.5.0-rc6+ #432
> >> "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> >> kvm-vcpu-0      D ffffffc000086bcc     0  1123   1114 0x00000008
> >> Call trace:
> >> [<ffffffc000086bcc>] __switch_to+0x90/0xa4
> >> [<ffffffc0006c4390>] __schedule+0x188/0x59c
> >> [<ffffffc0006c47e0>] schedule+0x3c/0xa0
> >> [<ffffffc0006c4bf4>] schedule_preempt_disabled+0x20/0x38
> >> [<ffffffc0006c618c>] __mutex_lock_slowpath+0xc4/0x148
> >> [<ffffffc0006c6254>] mutex_lock+0x44/0x5c
> >> [<ffffffc0000aacb8>] kvm_vgic_destroy+0x20/0xb0
> >> [<ffffffc0000abbdc>] vgic_v3_map_resources+0xa8/0xf0
> >> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
> >> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
> >> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
> >> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
> >> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
> >> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
> >>
> > 
> > Is this also with many many VCPUs or in general?
> > 
> 
> It's seen with many many VCPUs. Basically, I see
> 
> kvm [1273]: Unable to register VGICv3 redist MMIO regions
> 
> and then (if I'm patient enough) I see that backtrace. So the flow looks
> like:
> 
> el0_svc_naked
> ...
> vgic_v3_map_resources
>    vgic_register_redist_regions
>        kvm_vgic_register_mmio_region
>            kvm_io_bus_register_dev	// return -ENOSPC
>    kvm_vgic_destroy
>        mutex_lock
> 

ok, thanks for the clarification!

-Christoffer

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-30 19:53             ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30 19:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Mar 30, 2016 at 03:13:20PM +0100, Vladimir Murzin wrote:
> On 30/03/16 14:56, Christoffer Dall wrote:
> > Hi Vladimir,
> > 
> > On Wed, Mar 30, 2016 at 12:52:27PM +0100, Vladimir Murzin wrote:
> >> On 30/03/16 12:42, Vladimir Murzin wrote:
> >>> On 29/03/16 14:12, Vladimir Murzin wrote:
> >>>> Hi Andre,
> >>>>
> >>>> On 25/03/16 02:04, Andre Przywara wrote:
> >>>>> Please have a look at the series, review it and give the code some
> >>>>> serious testing (and possibly debugging). All feedback is appreciated.
> >>>>
> >>>> I see that with the new vgic implementation kvmtool starts throwing:
> >>>>
> >>>> kvm [1273]: Unable to register VGICv3 redist MMIO regions
> >>>>
> >>>
> >>> It comes from kvm_io_bus_register_dev()
> >>>
> >>> if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
> >>> 	return -ENOSPC;
> >>>
> >>> with bus->dev_count being 1000
> >>>
> >>> [<ffffffc00009f93c>] kvm_io_bus_register_dev+0x130/0x148
> >>> [<ffffffc0000ad274>] kvm_vgic_register_mmio_region+0xac/0xdc
> >>> [<ffffffc0000ad4d4>] vgic_register_redist_regions+0xb8/0x158
> >>> [<ffffffc0000abb90>] vgic_v3_map_resources+0x5c/0xf0
> >>> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
> >>> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
> >>> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
> >>> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
> >>> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
> >>> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
> >>>
> >>
> >> and one more thing I've forgotten to mention... something odd happens on
> >> destroy path
> >>
> >> INFO: task kvm-vcpu-0:1123 blocked for more than 120 seconds.
> >>       Tainted: G        W       4.5.0-rc6+ #432
> >> "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> >> kvm-vcpu-0      D ffffffc000086bcc     0  1123   1114 0x00000008
> >> Call trace:
> >> [<ffffffc000086bcc>] __switch_to+0x90/0xa4
> >> [<ffffffc0006c4390>] __schedule+0x188/0x59c
> >> [<ffffffc0006c47e0>] schedule+0x3c/0xa0
> >> [<ffffffc0006c4bf4>] schedule_preempt_disabled+0x20/0x38
> >> [<ffffffc0006c618c>] __mutex_lock_slowpath+0xc4/0x148
> >> [<ffffffc0006c6254>] mutex_lock+0x44/0x5c
> >> [<ffffffc0000aacb8>] kvm_vgic_destroy+0x20/0xb0
> >> [<ffffffc0000abbdc>] vgic_v3_map_resources+0xa8/0xf0
> >> [<ffffffc0000aae04>] kvm_vgic_map_resources+0x40/0x84
> >> [<ffffffc0000a23d0>] kvm_arch_vcpu_ioctl_run+0x3f0/0x400
> >> [<ffffffc00009d484>] kvm_vcpu_ioctl+0x2d4/0x6ec
> >> [<ffffffc0001c4eec>] do_vfs_ioctl+0xb4/0x760
> >> [<ffffffc0001c561c>] SyS_ioctl+0x84/0x98
> >> [<ffffffc000085d30>] el0_svc_naked+0x24/0x28
> >>
> > 
> > Is this also with many many VCPUs or in general?
> > 
> 
> It's seen with many many VCPUs. Basically, I see
> 
> kvm [1273]: Unable to register VGICv3 redist MMIO regions
> 
> and then (if I'm patient enough) I see that backtrace. So the flow looks
> like:
> 
> el0_svc_naked
> ...
> vgic_v3_map_resources
>    vgic_register_redist_regions
>        kvm_vgic_register_mmio_region
>            kvm_io_bus_register_dev	// return -ENOSPC
>    kvm_vgic_destroy
>        mutex_lock
> 

ok, thanks for the clarification!

-Christoffer

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-30 12:07       ` Marc Zyngier
@ 2016-03-30 19:55         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30 19:55 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Vladimir Murzin, Andre Przywara, Eric Auger, kvmarm,
	linux-arm-kernel, kvm

On Wed, Mar 30, 2016 at 01:07:06PM +0100, Marc Zyngier wrote:
> On 30/03/16 12:42, Vladimir Murzin wrote:
> > On 29/03/16 14:12, Vladimir Murzin wrote:
> >> Hi Andre,
> >>
> >> On 25/03/16 02:04, Andre Przywara wrote:
> >>> Please have a look at the series, review it and give the code some
> >>> serious testing (and possibly debugging). All feedback is appreciated.
> >>
> >> I see that with the new vgic implementation kvmtool starts throwing:
> >>
> >> kvm [1273]: Unable to register VGICv3 redist MMIO regions
> >>
> > 
> > It comes from kvm_io_bus_register_dev()
> > 
> > if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
> > 	return -ENOSPC;
> > 
> > with bus->dev_count being 1000
> 
> Ouch. That's a consequence of having one "device" per actual register
> set, I believe. So either we bump this limit up by a factor 10 (at
> least), or we switch back to the old way of handling access to the GIC
> regions (big "catch-all", and further demuxing).
> 
> Thoughts?
> 
Since we have to have code to iterate through the individual register
regions for the userland MMIO accesses anyway, I think we should just
revert back to the old way.

-Christoffer

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-30 19:55         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30 19:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Mar 30, 2016 at 01:07:06PM +0100, Marc Zyngier wrote:
> On 30/03/16 12:42, Vladimir Murzin wrote:
> > On 29/03/16 14:12, Vladimir Murzin wrote:
> >> Hi Andre,
> >>
> >> On 25/03/16 02:04, Andre Przywara wrote:
> >>> Please have a look at the series, review it and give the code some
> >>> serious testing (and possibly debugging). All feedback is appreciated.
> >>
> >> I see that with the new vgic implementation kvmtool starts throwing:
> >>
> >> kvm [1273]: Unable to register VGICv3 redist MMIO regions
> >>
> > 
> > It comes from kvm_io_bus_register_dev()
> > 
> > if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
> > 	return -ENOSPC;
> > 
> > with bus->dev_count being 1000
> 
> Ouch. That's a consequence of having one "device" per actual register
> set, I believe. So either we bump this limit up by a factor 10 (at
> least), or we switch back to the old way of handling access to the GIC
> regions (big "catch-all", and further demuxing).
> 
> Thoughts?
> 
Since we have to have code to iterate through the individual register
regions for the userland MMIO accesses anyway, I think we should just
revert back to the old way.

-Christoffer

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

* Re: [RFC PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-30 20:40     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30 20:40 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:04:33AM +0000, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> As the GICv3 virtual interface registers differ from their GICv2
> siblings, we need different handlers for processing maintenance
> interrupts and reading/writing to the LRs.
> Also as we store an IRQ's affinity directly as a MPIDR, we need a
> separate change_affinity() implementation too.

not sure why we embed the vgic_v3_irq_change_affinity in this patch here
and had a stand-alone patch for v2?

I think it would be better to split them up and again have one patch to
introduce the infrastructure for some piece of functionality, followed
by 2 patches, one plugging in the v2 part, the other plugging in the v3
part.


> Implement the respective handler functions and connect them to
> existing code to be called if the host is using a GICv3.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-v3.c | 191 ++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c    |   8 +-
>  virt/kvm/arm/vgic/vgic.h    |  30 +++++++
>  3 files changed, 225 insertions(+), 4 deletions(-)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> new file mode 100644
> index 0000000..71b4bad
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -0,0 +1,191 @@
> +/*
> + * 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/irqchip/arm-gic-v3.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <linux/irqchip/arm-gic.h>
> +
> +#include "vgic.h"
> +
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +
> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
> +		int lr;
> +
> +		for_each_set_bit(lr, &eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> +			u32 intid;
> +			u64 val = cpuif->vgic_lr[lr];
> +
> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +			else
> +				intid = val & GICH_LR_VIRTUALID;
> +
> +			/*
> +			 * kvm_notify_acked_irq calls kvm_set_irq()
> +			 * to reset the IRQ level, which grabs the dist->lock
> +			 * so we call this before taking the dist->lock.
> +			 */

this comment clearly doesn't apply anymore.

also, looking at the similarities here with the v2 code, we should
probably have another look at sharing some more code between v2 and v3.

> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
> +			cpuif->vgic_lr[lr] &= ~ICH_LR_STATE; /* Useful?? */

here you don't have the WARN that you had in v2, so does this mean we
can actually come here with the LR state field having some value?

> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +
> +		/*
> +		 * In the next iterations of the vcpu loop, if we sync
> +		 * the vgic state after flushing it, but before
> +		 * entering the guest (this happens for pending
> +		 * signals and vmid rollovers), then make sure we
> +		 * don't pick up any old maintenance interrupts here.
> +		 */
> +		cpuif->vgic_eisr = 0;
> +	}
> +
> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;

like in the v2 case, I think this should be moved out of the process
maintenance function.

> +}
> +
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
> +}
> +
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	int lr;
> +
> +	/* Assumes ap_list_lock held */
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u64 val = cpuif->vgic_lr[lr];
> +		u32 intid;
> +		struct vgic_irq *irq;
> +
> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +		else
> +			intid = val & GICH_LR_VIRTUALID;
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & ICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (intid < VGIC_NR_SGIS &&
> +			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level irqs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & ICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/* Requires the irq to be locked already */
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	u64 val;
> +
> +	if (!irq) {
> +		val = 0;
> +		goto out;
> +	}
> +
> +	val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= ICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (irq->intid < VGIC_NR_SGIS &&
> +		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= ICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= ICH_LR_HW;
> +		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= ICH_LR_EOI;
> +	}

indeed this code looks very much like the v2 code, so maybe Marc had a
point when he argued for this being more shared between v2 and v3.  Is
there a nice way to do that without an intermediate LR representation?

> +
> +	/*
> +	 * Currently all guest IRQs are Group1, as Group0 would result
> +	 * in a FIQ in the guest, which it wouldn't expect.
> +	 * Eventually we want to make this configurable, so we may
> +	 * revisit this in the future.

I know we have something similar in the current code, but I actually
don't understand this.  If the IRQ is programmed to be group0, then the
guest *would* expect an FIQ, or?

Why is this not a matter of reading which group this IRQ is configured
to be?

> +	 */
> +	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +		val |= ICH_LR_GROUP;
> +
> +out:
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
> +}
> +
> +void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct vgic_irq *irq;
> +	struct kvm_vcpu *vcpu;
> +
> +	BUG_ON(intid <= VGIC_MAX_PRIVATE || intid > 1019);
> +	BUG_ON(dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3);

do we need the last BUG_ON?

> +
> +	irq = vgic_get_irq(kvm, NULL, intid);
> +	vcpu = kvm_mpidr_to_vcpu(kvm, mpidr);
> +
> +	spin_lock(&irq->irq_lock);
> +	irq->target_vcpu = vcpu;
> +	spin_unlock(&irq->irq_lock);
> +}


> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 90a85bf..9eb031e8 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -368,7 +368,7 @@ static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>  	if (kvm_vgic_global_state.type == VGIC_V2)
>  		vgic_v2_process_maintenance(vcpu);
>  	else
> -		WARN(1, "GICv3 Not Implemented\n");
> +		vgic_v3_process_maintenance(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> @@ -376,7 +376,7 @@ static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>  	if (kvm_vgic_global_state.type == VGIC_V2)
>  		vgic_v2_fold_lr_state(vcpu);
>  	else
> -		WARN(1, "GICv3 Not Implemented\n");
> +		vgic_v3_fold_lr_state(vcpu);
>  }
>  
>  /*
> @@ -390,7 +390,7 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>  	if (kvm_vgic_global_state.type == VGIC_V2)
>  		vgic_v2_populate_lr(vcpu, irq, lr);
>  	else
> -		WARN(1, "GICv3 Not Implemented\n");
> +		vgic_v3_populate_lr(vcpu, irq, lr);
>  }
>  
>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> @@ -398,7 +398,7 @@ static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>  	if (kvm_vgic_global_state.type == VGIC_V2)
>  		vgic_v2_set_underflow(vcpu);
>  	else
> -		WARN(1, "GICv3 Not Implemented\n");
> +		vgic_v3_set_underflow(vcpu);
>  }
>  
>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 95ef3cf..53730ba 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -26,4 +26,34 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +#else
> +static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
> +					       u64 mpidr)
> +{
> +}
> +
> +static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
> +				       struct vgic_irq *irq, int lr)
> +{
> +}
> +
> +static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +#endif
> +
>  #endif
> -- 
> 2.7.3
> 

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

* [RFC PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-03-30 20:40     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-30 20:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:33AM +0000, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> As the GICv3 virtual interface registers differ from their GICv2
> siblings, we need different handlers for processing maintenance
> interrupts and reading/writing to the LRs.
> Also as we store an IRQ's affinity directly as a MPIDR, we need a
> separate change_affinity() implementation too.

not sure why we embed the vgic_v3_irq_change_affinity in this patch here
and had a stand-alone patch for v2?

I think it would be better to split them up and again have one patch to
introduce the infrastructure for some piece of functionality, followed
by 2 patches, one plugging in the v2 part, the other plugging in the v3
part.


> Implement the respective handler functions and connect them to
> existing code to be called if the host is using a GICv3.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-v3.c | 191 ++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c    |   8 +-
>  virt/kvm/arm/vgic/vgic.h    |  30 +++++++
>  3 files changed, 225 insertions(+), 4 deletions(-)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> new file mode 100644
> index 0000000..71b4bad
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -0,0 +1,191 @@
> +/*
> + * 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/irqchip/arm-gic-v3.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <linux/irqchip/arm-gic.h>
> +
> +#include "vgic.h"
> +
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +
> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
> +		int lr;
> +
> +		for_each_set_bit(lr, &eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> +			u32 intid;
> +			u64 val = cpuif->vgic_lr[lr];
> +
> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +			else
> +				intid = val & GICH_LR_VIRTUALID;
> +
> +			/*
> +			 * kvm_notify_acked_irq calls kvm_set_irq()
> +			 * to reset the IRQ level, which grabs the dist->lock
> +			 * so we call this before taking the dist->lock.
> +			 */

this comment clearly doesn't apply anymore.

also, looking at the similarities here with the v2 code, we should
probably have another look at sharing some more code between v2 and v3.

> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
> +			cpuif->vgic_lr[lr] &= ~ICH_LR_STATE; /* Useful?? */

here you don't have the WARN that you had in v2, so does this mean we
can actually come here with the LR state field having some value?

> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +
> +		/*
> +		 * In the next iterations of the vcpu loop, if we sync
> +		 * the vgic state after flushing it, but before
> +		 * entering the guest (this happens for pending
> +		 * signals and vmid rollovers), then make sure we
> +		 * don't pick up any old maintenance interrupts here.
> +		 */
> +		cpuif->vgic_eisr = 0;
> +	}
> +
> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;

like in the v2 case, I think this should be moved out of the process
maintenance function.

> +}
> +
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
> +}
> +
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	int lr;
> +
> +	/* Assumes ap_list_lock held */
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u64 val = cpuif->vgic_lr[lr];
> +		u32 intid;
> +		struct vgic_irq *irq;
> +
> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +		else
> +			intid = val & GICH_LR_VIRTUALID;
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & ICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (intid < VGIC_NR_SGIS &&
> +			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level irqs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & ICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/* Requires the irq to be locked already */
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	u64 val;
> +
> +	if (!irq) {
> +		val = 0;
> +		goto out;
> +	}
> +
> +	val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= ICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (irq->intid < VGIC_NR_SGIS &&
> +		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= ICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= ICH_LR_HW;
> +		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= ICH_LR_EOI;
> +	}

indeed this code looks very much like the v2 code, so maybe Marc had a
point when he argued for this being more shared between v2 and v3.  Is
there a nice way to do that without an intermediate LR representation?

> +
> +	/*
> +	 * Currently all guest IRQs are Group1, as Group0 would result
> +	 * in a FIQ in the guest, which it wouldn't expect.
> +	 * Eventually we want to make this configurable, so we may
> +	 * revisit this in the future.

I know we have something similar in the current code, but I actually
don't understand this.  If the IRQ is programmed to be group0, then the
guest *would* expect an FIQ, or?

Why is this not a matter of reading which group this IRQ is configured
to be?

> +	 */
> +	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +		val |= ICH_LR_GROUP;
> +
> +out:
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
> +}
> +
> +void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct vgic_irq *irq;
> +	struct kvm_vcpu *vcpu;
> +
> +	BUG_ON(intid <= VGIC_MAX_PRIVATE || intid > 1019);
> +	BUG_ON(dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3);

do we need the last BUG_ON?

> +
> +	irq = vgic_get_irq(kvm, NULL, intid);
> +	vcpu = kvm_mpidr_to_vcpu(kvm, mpidr);
> +
> +	spin_lock(&irq->irq_lock);
> +	irq->target_vcpu = vcpu;
> +	spin_unlock(&irq->irq_lock);
> +}


> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 90a85bf..9eb031e8 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -368,7 +368,7 @@ static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>  	if (kvm_vgic_global_state.type == VGIC_V2)
>  		vgic_v2_process_maintenance(vcpu);
>  	else
> -		WARN(1, "GICv3 Not Implemented\n");
> +		vgic_v3_process_maintenance(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> @@ -376,7 +376,7 @@ static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>  	if (kvm_vgic_global_state.type == VGIC_V2)
>  		vgic_v2_fold_lr_state(vcpu);
>  	else
> -		WARN(1, "GICv3 Not Implemented\n");
> +		vgic_v3_fold_lr_state(vcpu);
>  }
>  
>  /*
> @@ -390,7 +390,7 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>  	if (kvm_vgic_global_state.type == VGIC_V2)
>  		vgic_v2_populate_lr(vcpu, irq, lr);
>  	else
> -		WARN(1, "GICv3 Not Implemented\n");
> +		vgic_v3_populate_lr(vcpu, irq, lr);
>  }
>  
>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> @@ -398,7 +398,7 @@ static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>  	if (kvm_vgic_global_state.type == VGIC_V2)
>  		vgic_v2_set_underflow(vcpu);
>  	else
> -		WARN(1, "GICv3 Not Implemented\n");
> +		vgic_v3_set_underflow(vcpu);
>  }
>  
>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 95ef3cf..53730ba 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -26,4 +26,34 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +#else
> +static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
> +					       u64 mpidr)
> +{
> +}
> +
> +static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
> +				       struct vgic_irq *irq, int lr)
> +{
> +}
> +
> +static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +#endif
> +
>  #endif
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 11/45] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31  8:54     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  8:54 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:04:34AM +0000, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> Tell KVM whether a particular VCPU has an IRQ that needs handling
> in the guest. This is used to decide whether a VCPU is runnable.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h  |  2 ++
>  virt/kvm/arm/vgic/vgic.c | 22 ++++++++++++++++++++++
>  2 files changed, 24 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 986f23f..2ce9b4a 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -181,6 +181,8 @@ struct vgic_cpu {
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level);
>  
> +int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
> +
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(false)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 9eb031e8..d6c8c92 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -477,3 +477,25 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>  	vgic_populate_lrs(vcpu);
>  	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>  }
> +
> +int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	bool pending = false;
> +
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		pending = irq->pending && irq->enabled;
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (pending)
> +			break;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +	return pending;
> +}

as long as we only call this in the wfi/wfe path, then it's fine.  If we
start calling this in the critical path, I think we should check the
common case of list_empty(&vgic_cpu->ap_list) first.


Thanks,
-Christoffer

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

* [RFC PATCH 11/45] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
@ 2016-03-31  8:54     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  8:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:34AM +0000, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> Tell KVM whether a particular VCPU has an IRQ that needs handling
> in the guest. This is used to decide whether a VCPU is runnable.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h  |  2 ++
>  virt/kvm/arm/vgic/vgic.c | 22 ++++++++++++++++++++++
>  2 files changed, 24 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 986f23f..2ce9b4a 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -181,6 +181,8 @@ struct vgic_cpu {
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level);
>  
> +int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
> +
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(false)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 9eb031e8..d6c8c92 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -477,3 +477,25 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>  	vgic_populate_lrs(vcpu);
>  	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>  }
> +
> +int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	bool pending = false;
> +
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		pending = irq->pending && irq->enabled;
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (pending)
> +			break;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +	return pending;
> +}

as long as we only call this in the wfi/wfe path, then it's fine.  If we
start calling this in the critical path, I think we should check the
common case of list_empty(&vgic_cpu->ap_list) first.


Thanks,
-Christoffer

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-30 19:55         ` Christoffer Dall
@ 2016-03-31  9:06           ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2016-03-31  9:06 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Vladimir Murzin, Andre Przywara, Eric Auger, kvmarm,
	linux-arm-kernel, kvm

On 30/03/16 20:55, Christoffer Dall wrote:
> On Wed, Mar 30, 2016 at 01:07:06PM +0100, Marc Zyngier wrote:
>> On 30/03/16 12:42, Vladimir Murzin wrote:
>>> On 29/03/16 14:12, Vladimir Murzin wrote:
>>>> Hi Andre,
>>>>
>>>> On 25/03/16 02:04, Andre Przywara wrote:
>>>>> Please have a look at the series, review it and give the code some
>>>>> serious testing (and possibly debugging). All feedback is appreciated.
>>>>
>>>> I see that with the new vgic implementation kvmtool starts throwing:
>>>>
>>>> kvm [1273]: Unable to register VGICv3 redist MMIO regions
>>>>
>>>
>>> It comes from kvm_io_bus_register_dev()
>>>
>>> if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
>>> 	return -ENOSPC;
>>>
>>> with bus->dev_count being 1000
>>
>> Ouch. That's a consequence of having one "device" per actual register
>> set, I believe. So either we bump this limit up by a factor 10 (at
>> least), or we switch back to the old way of handling access to the GIC
>> regions (big "catch-all", and further demuxing).
>>
>> Thoughts?
>>
> Since we have to have code to iterate through the individual register
> regions for the userland MMIO accesses anyway, I think we should just
> revert back to the old way.

That's what I was thinking as well. We could use a binary search to
speed-up the "in-region" search, just like the kvm_io_bus stuff does.

Thanks,

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

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-31  9:06           ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2016-03-31  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

On 30/03/16 20:55, Christoffer Dall wrote:
> On Wed, Mar 30, 2016 at 01:07:06PM +0100, Marc Zyngier wrote:
>> On 30/03/16 12:42, Vladimir Murzin wrote:
>>> On 29/03/16 14:12, Vladimir Murzin wrote:
>>>> Hi Andre,
>>>>
>>>> On 25/03/16 02:04, Andre Przywara wrote:
>>>>> Please have a look at the series, review it and give the code some
>>>>> serious testing (and possibly debugging). All feedback is appreciated.
>>>>
>>>> I see that with the new vgic implementation kvmtool starts throwing:
>>>>
>>>> kvm [1273]: Unable to register VGICv3 redist MMIO regions
>>>>
>>>
>>> It comes from kvm_io_bus_register_dev()
>>>
>>> if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
>>> 	return -ENOSPC;
>>>
>>> with bus->dev_count being 1000
>>
>> Ouch. That's a consequence of having one "device" per actual register
>> set, I believe. So either we bump this limit up by a factor 10 (at
>> least), or we switch back to the old way of handling access to the GIC
>> regions (big "catch-all", and further demuxing).
>>
>> Thoughts?
>>
> Since we have to have code to iterate through the individual register
> regions for the userland MMIO accesses anyway, I think we should just
> revert back to the old way.

That's what I was thinking as well. We could use a binary search to
speed-up the "in-region" search, just like the kvm_io_bus stuff does.

Thanks,

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

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

* Re: [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31  9:08     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:08 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, kvm, kvmarm, linux-arm-kernel

Hi Andre,

[cc'ing Paolo here for his thoughts on the KVM IO bus framework]

On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
> We register each register group of the distributor and redistributors
> as separate regions of the kvm-io-bus framework. This way calls get
> directly handed over to the actual handler.
> This puts a lot more regions into kvm-io-bus than what we use at the
> moment on other architectures, so we will probably need to revisit the
> implementation of the framework later to be more efficient.

Looking more carefully at the KVM IO bus stuff, it looks like it is
indeed designed to be a *per device* thing you register, not a *per
register* thing.

My comments to Vladimir's bug report notwithstanding, there's still a
choice here to:

1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices

2) Build a KVM architectureal generic framework on top of the IO bus
framework to handle individual register regions.

3) Stick with what we had before, do not modify the KVM IO bus stuff,
and handle the individual register region business locally within the
arm/vgic code.


> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> ---
>  include/kvm/vgic/vgic.h       |   9 ++
>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
>  3 files changed, 250 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2ce9b4a..a8262c7 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -106,6 +106,12 @@ struct vgic_irq {
>  	enum vgic_irq_config config;	/* Level or edge */
>  };
>  
> +struct vgic_io_device {
> +	gpa_t base_addr;
> +	struct kvm_vcpu *redist_vcpu;
> +	struct kvm_io_device dev;
> +};
> +
>  struct vgic_dist {
>  	bool			in_kernel;
>  	bool			ready;
> @@ -132,6 +138,9 @@ struct vgic_dist {
>  	u32			enabled;
>  
>  	struct vgic_irq		*spis;
> +
> +	struct vgic_io_device	*dist_iodevs;
> +	struct vgic_io_device	*redist_iodevs;
>  };
>  
>  struct vgic_v2_cpu_if {
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> new file mode 100644
> index 0000000..26c46e7
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -0,0 +1,194 @@
> +/*
> + * VGIC MMIO handling functions
> + *
> + * 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.
> + */
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/iodev.h>
> +#include <kvm/vgic/vgic.h>
> +#include <linux/bitops.h>
> +#include <linux/irqchip/arm-gic.h>
> +
> +#include "vgic.h"
> +#include "vgic_mmio.h"
> +
> +void write_mask32(u32 value, int offset, int len, void *val)
> +{
> +	value = cpu_to_le32(value) >> (offset * 8);
> +	memcpy(val, &value, len);
> +}
> +
> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
> +{
> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
> +	memcpy((char *)&origvalue + (offset * 8), val, len);
> +	return origvalue;
> +}
> +
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void write_mask64(u64 value, int offset, int len, void *val)
> +{
> +	value = cpu_to_le64(value) >> (offset * 8);
> +	memcpy(val, &value, len);
> +}
> +
> +/* FIXME: I am clearly misguided here, there must be some saner way ... */

I'm confuses in general.  Can you explain what these mask functions do
overall at some higher level?

I also keep having a feeling that mixing endianness stuff into the
emulation code itself is the wrong way to go about it.  The emulation
code should just deal with register values of varying length and the
interface to the VGIC should abstract all endianness nonsense for us,
but I also think I've lost this argument some time in the past.  Sigh.

But, is the maximum read/write unit for any MMIO access not a 64-bit
value?  So why can't we let the VGIC emulation code simply take/return a
u64 which is then masked off/morphed into the right endianness outside
the VGIC code?

> +u64 mask64(u64 origvalue, int offset, int len, const void *val)
> +{
> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
> +	memcpy((char *)&origvalue + (offset * 8), val, len);
> +	return origvalue;
> +}
> +#endif
> +
> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
> +		       gpa_t addr, int len, void *val)
> +{
> +	memset(val, 0, len);
> +
> +	return 0;
> +}
> +
> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
> +		       gpa_t addr, int len, const void *val)
> +{
> +	return 0;
> +}

I dislike the use of 'this' as a parameter name, why not 'dev' ?

> +
> +static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
> +			      struct kvm_io_device *this,
> +			      gpa_t addr, int len, void *val)
> +{
> +	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
> +		vcpu->vcpu_id, (unsigned long long)addr);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
> +			       struct kvm_io_device *this,
> +			       gpa_t addr, int len, const void *val)
> +{
> +	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
> +		vcpu->vcpu_id, (unsigned long long)addr);
> +	return 0;
> +}
> +
> +struct vgic_register_region vgic_v2_dist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
> +};
> +
> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +				  struct vgic_register_region *reg_desc,
> +				  struct vgic_io_device *region,
> +				  int nr_irqs, bool offset_private)
> +{
> +	int bpi = reg_desc->bits_per_irq;
> +	int offset = 0;
> +	int len, ret;
> +
> +	region->base_addr	+= reg_desc->reg_offset;
> +	region->redist_vcpu	= vcpu;
> +
> +	kvm_iodevice_init(&region->dev, &reg_desc->ops);
> +
> +	if (bpi) {
> +		len = (bpi * nr_irqs) / 8;
> +		if (offset_private)
> +			offset = (bpi * VGIC_NR_PRIVATE_IRQS) / 8;
> +	} else {
> +		len = reg_desc->len;
> +	}
> +
> +	mutex_lock(&kvm->slots_lock);
> +	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +				      region->base_addr + offset,
> +				      len - offset, &region->dev);
> +	mutex_unlock(&kvm->slots_lock);
> +
> +	return ret;
> +}
> +
> +int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
> +			       enum vgic_type type)
> +{
> +	struct vgic_io_device *regions;
> +	struct vgic_register_region *reg_desc;
> +	int nr_regions;
> +	int nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +	int i;
> +	int ret = 0;
> +
> +	switch (type) {
> +	case VGIC_V2:
> +		reg_desc = vgic_v2_dist_registers;
> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> +		break;
> +	default:
> +		BUG_ON(1);
> +	}
> +
> +	regions = kmalloc_array(nr_regions, sizeof(struct vgic_io_device),
> +				GFP_KERNEL);
> +	if (!regions)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < nr_regions; i++) {
> +		regions[i].base_addr	= dist_base_address;
> +
> +		ret = kvm_vgic_register_mmio_region(kvm, NULL, reg_desc,
> +						    regions + i, nr_irqs,
> +						    type == VGIC_V3);
> +		if (ret)
> +			break;
> +
> +		reg_desc++;
> +	}
> +
> +	if (ret) {
> +		mutex_lock(&kvm->slots_lock);
> +		for (i--; i >= 0; i--)
> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &regions[i].dev);
> +		mutex_unlock(&kvm->slots_lock);
> +	} else {
> +		kvm->arch.vgic.dist_iodevs = regions;
> +	}
> +
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.h b/virt/kvm/arm/vgic/vgic_mmio.h
> new file mode 100644
> index 0000000..cf2314c
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic_mmio.h
> @@ -0,0 +1,47 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * 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_ARM_VGIC_MMIO_H__
> +#define __KVM_ARM_VGIC_MMIO_H__
> +
> +struct vgic_register_region {
> +	int reg_offset;
> +	int len;
> +	int bits_per_irq;
> +	struct kvm_io_device_ops ops;
> +};
> +
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(name, read_ops, write_ops, bpi) \
> +	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
> +	 .ops.read = read_ops, .ops.write = write_ops}
> +#define REGISTER_DESC_WITH_LENGTH(name, read_ops, write_ops, length) \
> +	{.reg_offset = name, .bits_per_irq = 0, .len = length, \
> +	 .ops.read = read_ops, .ops.write = write_ops}
> +
> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
> +		       gpa_t addr, int len, void *val);
> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
> +		       gpa_t addr, int len, const void *val);
> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +				  struct vgic_register_region *reg_desc,
> +				  struct vgic_io_device *region,
> +				  int nr_irqs, bool offset_private);
> +
> +void write_mask32(u32 value, int offset, int len, void *val);
> +void write_mask64(u64 value, int offset, int len, void *val);
> +u32 mask32(u32 origvalue, int offset, int len, const void *val);
> +u64 mask64(u64 origvalue, int offset, int len, const void *val);
> +
> +#endif
> -- 
> 2.7.3
> 
> 

Thanks,
-Christoffer

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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-03-31  9:08     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:08 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andre,

[cc'ing Paolo here for his thoughts on the KVM IO bus framework]

On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
> We register each register group of the distributor and redistributors
> as separate regions of the kvm-io-bus framework. This way calls get
> directly handed over to the actual handler.
> This puts a lot more regions into kvm-io-bus than what we use at the
> moment on other architectures, so we will probably need to revisit the
> implementation of the framework later to be more efficient.

Looking more carefully at the KVM IO bus stuff, it looks like it is
indeed designed to be a *per device* thing you register, not a *per
register* thing.

My comments to Vladimir's bug report notwithstanding, there's still a
choice here to:

1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices

2) Build a KVM architectureal generic framework on top of the IO bus
framework to handle individual register regions.

3) Stick with what we had before, do not modify the KVM IO bus stuff,
and handle the individual register region business locally within the
arm/vgic code.


> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> ---
>  include/kvm/vgic/vgic.h       |   9 ++
>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
>  3 files changed, 250 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2ce9b4a..a8262c7 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -106,6 +106,12 @@ struct vgic_irq {
>  	enum vgic_irq_config config;	/* Level or edge */
>  };
>  
> +struct vgic_io_device {
> +	gpa_t base_addr;
> +	struct kvm_vcpu *redist_vcpu;
> +	struct kvm_io_device dev;
> +};
> +
>  struct vgic_dist {
>  	bool			in_kernel;
>  	bool			ready;
> @@ -132,6 +138,9 @@ struct vgic_dist {
>  	u32			enabled;
>  
>  	struct vgic_irq		*spis;
> +
> +	struct vgic_io_device	*dist_iodevs;
> +	struct vgic_io_device	*redist_iodevs;
>  };
>  
>  struct vgic_v2_cpu_if {
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> new file mode 100644
> index 0000000..26c46e7
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -0,0 +1,194 @@
> +/*
> + * VGIC MMIO handling functions
> + *
> + * 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.
> + */
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/iodev.h>
> +#include <kvm/vgic/vgic.h>
> +#include <linux/bitops.h>
> +#include <linux/irqchip/arm-gic.h>
> +
> +#include "vgic.h"
> +#include "vgic_mmio.h"
> +
> +void write_mask32(u32 value, int offset, int len, void *val)
> +{
> +	value = cpu_to_le32(value) >> (offset * 8);
> +	memcpy(val, &value, len);
> +}
> +
> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
> +{
> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
> +	memcpy((char *)&origvalue + (offset * 8), val, len);
> +	return origvalue;
> +}
> +
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void write_mask64(u64 value, int offset, int len, void *val)
> +{
> +	value = cpu_to_le64(value) >> (offset * 8);
> +	memcpy(val, &value, len);
> +}
> +
> +/* FIXME: I am clearly misguided here, there must be some saner way ... */

I'm confuses in general.  Can you explain what these mask functions do
overall at some higher level?

I also keep having a feeling that mixing endianness stuff into the
emulation code itself is the wrong way to go about it.  The emulation
code should just deal with register values of varying length and the
interface to the VGIC should abstract all endianness nonsense for us,
but I also think I've lost this argument some time in the past.  Sigh.

But, is the maximum read/write unit for any MMIO access not a 64-bit
value?  So why can't we let the VGIC emulation code simply take/return a
u64 which is then masked off/morphed into the right endianness outside
the VGIC code?

> +u64 mask64(u64 origvalue, int offset, int len, const void *val)
> +{
> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
> +	memcpy((char *)&origvalue + (offset * 8), val, len);
> +	return origvalue;
> +}
> +#endif
> +
> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
> +		       gpa_t addr, int len, void *val)
> +{
> +	memset(val, 0, len);
> +
> +	return 0;
> +}
> +
> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
> +		       gpa_t addr, int len, const void *val)
> +{
> +	return 0;
> +}

I dislike the use of 'this' as a parameter name, why not 'dev' ?

> +
> +static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
> +			      struct kvm_io_device *this,
> +			      gpa_t addr, int len, void *val)
> +{
> +	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
> +		vcpu->vcpu_id, (unsigned long long)addr);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
> +			       struct kvm_io_device *this,
> +			       gpa_t addr, int len, const void *val)
> +{
> +	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
> +		vcpu->vcpu_id, (unsigned long long)addr);
> +	return 0;
> +}
> +
> +struct vgic_register_region vgic_v2_dist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
> +};
> +
> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +				  struct vgic_register_region *reg_desc,
> +				  struct vgic_io_device *region,
> +				  int nr_irqs, bool offset_private)
> +{
> +	int bpi = reg_desc->bits_per_irq;
> +	int offset = 0;
> +	int len, ret;
> +
> +	region->base_addr	+= reg_desc->reg_offset;
> +	region->redist_vcpu	= vcpu;
> +
> +	kvm_iodevice_init(&region->dev, &reg_desc->ops);
> +
> +	if (bpi) {
> +		len = (bpi * nr_irqs) / 8;
> +		if (offset_private)
> +			offset = (bpi * VGIC_NR_PRIVATE_IRQS) / 8;
> +	} else {
> +		len = reg_desc->len;
> +	}
> +
> +	mutex_lock(&kvm->slots_lock);
> +	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +				      region->base_addr + offset,
> +				      len - offset, &region->dev);
> +	mutex_unlock(&kvm->slots_lock);
> +
> +	return ret;
> +}
> +
> +int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
> +			       enum vgic_type type)
> +{
> +	struct vgic_io_device *regions;
> +	struct vgic_register_region *reg_desc;
> +	int nr_regions;
> +	int nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +	int i;
> +	int ret = 0;
> +
> +	switch (type) {
> +	case VGIC_V2:
> +		reg_desc = vgic_v2_dist_registers;
> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> +		break;
> +	default:
> +		BUG_ON(1);
> +	}
> +
> +	regions = kmalloc_array(nr_regions, sizeof(struct vgic_io_device),
> +				GFP_KERNEL);
> +	if (!regions)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < nr_regions; i++) {
> +		regions[i].base_addr	= dist_base_address;
> +
> +		ret = kvm_vgic_register_mmio_region(kvm, NULL, reg_desc,
> +						    regions + i, nr_irqs,
> +						    type == VGIC_V3);
> +		if (ret)
> +			break;
> +
> +		reg_desc++;
> +	}
> +
> +	if (ret) {
> +		mutex_lock(&kvm->slots_lock);
> +		for (i--; i >= 0; i--)
> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &regions[i].dev);
> +		mutex_unlock(&kvm->slots_lock);
> +	} else {
> +		kvm->arch.vgic.dist_iodevs = regions;
> +	}
> +
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.h b/virt/kvm/arm/vgic/vgic_mmio.h
> new file mode 100644
> index 0000000..cf2314c
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic_mmio.h
> @@ -0,0 +1,47 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * 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_ARM_VGIC_MMIO_H__
> +#define __KVM_ARM_VGIC_MMIO_H__
> +
> +struct vgic_register_region {
> +	int reg_offset;
> +	int len;
> +	int bits_per_irq;
> +	struct kvm_io_device_ops ops;
> +};
> +
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(name, read_ops, write_ops, bpi) \
> +	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
> +	 .ops.read = read_ops, .ops.write = write_ops}
> +#define REGISTER_DESC_WITH_LENGTH(name, read_ops, write_ops, length) \
> +	{.reg_offset = name, .bits_per_irq = 0, .len = length, \
> +	 .ops.read = read_ops, .ops.write = write_ops}
> +
> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
> +		       gpa_t addr, int len, void *val);
> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
> +		       gpa_t addr, int len, const void *val);
> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +				  struct vgic_register_region *reg_desc,
> +				  struct vgic_io_device *region,
> +				  int nr_irqs, bool offset_private);
> +
> +void write_mask32(u32 value, int offset, int len, void *val);
> +void write_mask64(u64 value, int offset, int len, void *val);
> +u32 mask32(u32 origvalue, int offset, int len, const void *val);
> +u64 mask64(u64 origvalue, int offset, int len, const void *val);
> +
> +#endif
> -- 
> 2.7.3
> 
> 

Thanks,
-Christoffer

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

* Re: [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-03-31  9:08     ` Christoffer Dall
@ 2016-03-31  9:09       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:09 UTC (permalink / raw)
  To: Andre Przywara; +Cc: kvm, Marc Zyngier, Paolo Bonzini, kvmarm, linux-arm-kernel

[really cc'ing Paolo this time]

On Thu, Mar 31, 2016 at 11:08 AM, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> Hi Andre,
>
> [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
>
> On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
>> We register each register group of the distributor and redistributors
>> as separate regions of the kvm-io-bus framework. This way calls get
>> directly handed over to the actual handler.
>> This puts a lot more regions into kvm-io-bus than what we use at the
>> moment on other architectures, so we will probably need to revisit the
>> implementation of the framework later to be more efficient.
>
> Looking more carefully at the KVM IO bus stuff, it looks like it is
> indeed designed to be a *per device* thing you register, not a *per
> register* thing.
>
> My comments to Vladimir's bug report notwithstanding, there's still a
> choice here to:
>
> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
>
> 2) Build a KVM architectureal generic framework on top of the IO bus
> framework to handle individual register regions.
>
> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> and handle the individual register region business locally within the
> arm/vgic code.
>
>
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> ---
>>  include/kvm/vgic/vgic.h       |   9 ++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
>>  3 files changed, 250 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 2ce9b4a..a8262c7 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -106,6 +106,12 @@ struct vgic_irq {
>>       enum vgic_irq_config config;    /* Level or edge */
>>  };
>>
>> +struct vgic_io_device {
>> +     gpa_t base_addr;
>> +     struct kvm_vcpu *redist_vcpu;
>> +     struct kvm_io_device dev;
>> +};
>> +
>>  struct vgic_dist {
>>       bool                    in_kernel;
>>       bool                    ready;
>> @@ -132,6 +138,9 @@ struct vgic_dist {
>>       u32                     enabled;
>>
>>       struct vgic_irq         *spis;
>> +
>> +     struct vgic_io_device   *dist_iodevs;
>> +     struct vgic_io_device   *redist_iodevs;
>>  };
>>
>>  struct vgic_v2_cpu_if {
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> new file mode 100644
>> index 0000000..26c46e7
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -0,0 +1,194 @@
>> +/*
>> + * VGIC MMIO handling functions
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <kvm/iodev.h>
>> +#include <kvm/vgic/vgic.h>
>> +#include <linux/bitops.h>
>> +#include <linux/irqchip/arm-gic.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic_mmio.h"
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val)
>> +{
>> +     value = cpu_to_le32(value) >> (offset * 8);
>> +     memcpy(val, &value, len);
>> +}
>> +
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
>> +{
>> +     origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +     memcpy((char *)&origvalue + (offset * 8), val, len);
>> +     return origvalue;
>> +}
>> +
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +void write_mask64(u64 value, int offset, int len, void *val)
>> +{
>> +     value = cpu_to_le64(value) >> (offset * 8);
>> +     memcpy(val, &value, len);
>> +}
>> +
>> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
>
> I'm confuses in general.  Can you explain what these mask functions do
> overall at some higher level?
>
> I also keep having a feeling that mixing endianness stuff into the
> emulation code itself is the wrong way to go about it.  The emulation
> code should just deal with register values of varying length and the
> interface to the VGIC should abstract all endianness nonsense for us,
> but I also think I've lost this argument some time in the past.  Sigh.
>
> But, is the maximum read/write unit for any MMIO access not a 64-bit
> value?  So why can't we let the VGIC emulation code simply take/return a
> u64 which is then masked off/morphed into the right endianness outside
> the VGIC code?
>
>> +u64 mask64(u64 origvalue, int offset, int len, const void *val)
>> +{
>> +     origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +     memcpy((char *)&origvalue + (offset * 8), val, len);
>> +     return origvalue;
>> +}
>> +#endif
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +                    gpa_t addr, int len, void *val)
>> +{
>> +     memset(val, 0, len);
>> +
>> +     return 0;
>> +}
>> +
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +                    gpa_t addr, int len, const void *val)
>> +{
>> +     return 0;
>> +}
>
> I dislike the use of 'this' as a parameter name, why not 'dev' ?
>
>> +
>> +static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
>> +                           struct kvm_io_device *this,
>> +                           gpa_t addr, int len, void *val)
>> +{
>> +     pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
>> +             vcpu->vcpu_id, (unsigned long long)addr);
>> +     return 0;
>> +}
>> +
>> +static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
>> +                            struct kvm_io_device *this,
>> +                            gpa_t addr, int len, const void *val)
>> +{
>> +     pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
>> +             vcpu->vcpu_id, (unsigned long long)addr);
>> +     return 0;
>> +}
>> +
>> +struct vgic_register_region vgic_v2_dist_registers[] = {
>> +     REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>> +             vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +     REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
>> +     REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +     REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +};
>> +
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +                               struct vgic_register_region *reg_desc,
>> +                               struct vgic_io_device *region,
>> +                               int nr_irqs, bool offset_private)
>> +{
>> +     int bpi = reg_desc->bits_per_irq;
>> +     int offset = 0;
>> +     int len, ret;
>> +
>> +     region->base_addr       += reg_desc->reg_offset;
>> +     region->redist_vcpu     = vcpu;
>> +
>> +     kvm_iodevice_init(&region->dev, &reg_desc->ops);
>> +
>> +     if (bpi) {
>> +             len = (bpi * nr_irqs) / 8;
>> +             if (offset_private)
>> +                     offset = (bpi * VGIC_NR_PRIVATE_IRQS) / 8;
>> +     } else {
>> +             len = reg_desc->len;
>> +     }
>> +
>> +     mutex_lock(&kvm->slots_lock);
>> +     ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +                                   region->base_addr + offset,
>> +                                   len - offset, &region->dev);
>> +     mutex_unlock(&kvm->slots_lock);
>> +
>> +     return ret;
>> +}
>> +
>> +int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>> +                            enum vgic_type type)
>> +{
>> +     struct vgic_io_device *regions;
>> +     struct vgic_register_region *reg_desc;
>> +     int nr_regions;
>> +     int nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +     int i;
>> +     int ret = 0;
>> +
>> +     switch (type) {
>> +     case VGIC_V2:
>> +             reg_desc = vgic_v2_dist_registers;
>> +             nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>> +             break;
>> +     default:
>> +             BUG_ON(1);
>> +     }
>> +
>> +     regions = kmalloc_array(nr_regions, sizeof(struct vgic_io_device),
>> +                             GFP_KERNEL);
>> +     if (!regions)
>> +             return -ENOMEM;
>> +
>> +     for (i = 0; i < nr_regions; i++) {
>> +             regions[i].base_addr    = dist_base_address;
>> +
>> +             ret = kvm_vgic_register_mmio_region(kvm, NULL, reg_desc,
>> +                                                 regions + i, nr_irqs,
>> +                                                 type == VGIC_V3);
>> +             if (ret)
>> +                     break;
>> +
>> +             reg_desc++;
>> +     }
>> +
>> +     if (ret) {
>> +             mutex_lock(&kvm->slots_lock);
>> +             for (i--; i >= 0; i--)
>> +                     kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +                                               &regions[i].dev);
>> +             mutex_unlock(&kvm->slots_lock);
>> +     } else {
>> +             kvm->arch.vgic.dist_iodevs = regions;
>> +     }
>> +
>> +     return ret;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.h b/virt/kvm/arm/vgic/vgic_mmio.h
>> new file mode 100644
>> index 0000000..cf2314c
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.h
>> @@ -0,0 +1,47 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * 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_ARM_VGIC_MMIO_H__
>> +#define __KVM_ARM_VGIC_MMIO_H__
>> +
>> +struct vgic_register_region {
>> +     int reg_offset;
>> +     int len;
>> +     int bits_per_irq;
>> +     struct kvm_io_device_ops ops;
>> +};
>> +
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(name, read_ops, write_ops, bpi) \
>> +     {.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
>> +      .ops.read = read_ops, .ops.write = write_ops}
>> +#define REGISTER_DESC_WITH_LENGTH(name, read_ops, write_ops, length) \
>> +     {.reg_offset = name, .bits_per_irq = 0, .len = length, \
>> +      .ops.read = read_ops, .ops.write = write_ops}
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +                    gpa_t addr, int len, void *val);
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +                    gpa_t addr, int len, const void *val);
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +                               struct vgic_register_region *reg_desc,
>> +                               struct vgic_io_device *region,
>> +                               int nr_irqs, bool offset_private);
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val);
>> +void write_mask64(u64 value, int offset, int len, void *val);
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val);
>> +u64 mask64(u64 origvalue, int offset, int len, const void *val);
>> +
>> +#endif
>> --
>> 2.7.3
>>
>>
>
> Thanks,
> -Christoffer

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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-03-31  9:09       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

[really cc'ing Paolo this time]

On Thu, Mar 31, 2016 at 11:08 AM, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> Hi Andre,
>
> [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
>
> On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
>> We register each register group of the distributor and redistributors
>> as separate regions of the kvm-io-bus framework. This way calls get
>> directly handed over to the actual handler.
>> This puts a lot more regions into kvm-io-bus than what we use at the
>> moment on other architectures, so we will probably need to revisit the
>> implementation of the framework later to be more efficient.
>
> Looking more carefully at the KVM IO bus stuff, it looks like it is
> indeed designed to be a *per device* thing you register, not a *per
> register* thing.
>
> My comments to Vladimir's bug report notwithstanding, there's still a
> choice here to:
>
> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
>
> 2) Build a KVM architectureal generic framework on top of the IO bus
> framework to handle individual register regions.
>
> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> and handle the individual register region business locally within the
> arm/vgic code.
>
>
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> ---
>>  include/kvm/vgic/vgic.h       |   9 ++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
>>  3 files changed, 250 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 2ce9b4a..a8262c7 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -106,6 +106,12 @@ struct vgic_irq {
>>       enum vgic_irq_config config;    /* Level or edge */
>>  };
>>
>> +struct vgic_io_device {
>> +     gpa_t base_addr;
>> +     struct kvm_vcpu *redist_vcpu;
>> +     struct kvm_io_device dev;
>> +};
>> +
>>  struct vgic_dist {
>>       bool                    in_kernel;
>>       bool                    ready;
>> @@ -132,6 +138,9 @@ struct vgic_dist {
>>       u32                     enabled;
>>
>>       struct vgic_irq         *spis;
>> +
>> +     struct vgic_io_device   *dist_iodevs;
>> +     struct vgic_io_device   *redist_iodevs;
>>  };
>>
>>  struct vgic_v2_cpu_if {
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> new file mode 100644
>> index 0000000..26c46e7
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -0,0 +1,194 @@
>> +/*
>> + * VGIC MMIO handling functions
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <kvm/iodev.h>
>> +#include <kvm/vgic/vgic.h>
>> +#include <linux/bitops.h>
>> +#include <linux/irqchip/arm-gic.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic_mmio.h"
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val)
>> +{
>> +     value = cpu_to_le32(value) >> (offset * 8);
>> +     memcpy(val, &value, len);
>> +}
>> +
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
>> +{
>> +     origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +     memcpy((char *)&origvalue + (offset * 8), val, len);
>> +     return origvalue;
>> +}
>> +
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +void write_mask64(u64 value, int offset, int len, void *val)
>> +{
>> +     value = cpu_to_le64(value) >> (offset * 8);
>> +     memcpy(val, &value, len);
>> +}
>> +
>> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
>
> I'm confuses in general.  Can you explain what these mask functions do
> overall at some higher level?
>
> I also keep having a feeling that mixing endianness stuff into the
> emulation code itself is the wrong way to go about it.  The emulation
> code should just deal with register values of varying length and the
> interface to the VGIC should abstract all endianness nonsense for us,
> but I also think I've lost this argument some time in the past.  Sigh.
>
> But, is the maximum read/write unit for any MMIO access not a 64-bit
> value?  So why can't we let the VGIC emulation code simply take/return a
> u64 which is then masked off/morphed into the right endianness outside
> the VGIC code?
>
>> +u64 mask64(u64 origvalue, int offset, int len, const void *val)
>> +{
>> +     origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +     memcpy((char *)&origvalue + (offset * 8), val, len);
>> +     return origvalue;
>> +}
>> +#endif
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +                    gpa_t addr, int len, void *val)
>> +{
>> +     memset(val, 0, len);
>> +
>> +     return 0;
>> +}
>> +
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +                    gpa_t addr, int len, const void *val)
>> +{
>> +     return 0;
>> +}
>
> I dislike the use of 'this' as a parameter name, why not 'dev' ?
>
>> +
>> +static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
>> +                           struct kvm_io_device *this,
>> +                           gpa_t addr, int len, void *val)
>> +{
>> +     pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
>> +             vcpu->vcpu_id, (unsigned long long)addr);
>> +     return 0;
>> +}
>> +
>> +static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
>> +                            struct kvm_io_device *this,
>> +                            gpa_t addr, int len, const void *val)
>> +{
>> +     pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
>> +             vcpu->vcpu_id, (unsigned long long)addr);
>> +     return 0;
>> +}
>> +
>> +struct vgic_register_region vgic_v2_dist_registers[] = {
>> +     REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>> +             vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +     REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +     REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
>> +     REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +     REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
>> +             vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +};
>> +
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +                               struct vgic_register_region *reg_desc,
>> +                               struct vgic_io_device *region,
>> +                               int nr_irqs, bool offset_private)
>> +{
>> +     int bpi = reg_desc->bits_per_irq;
>> +     int offset = 0;
>> +     int len, ret;
>> +
>> +     region->base_addr       += reg_desc->reg_offset;
>> +     region->redist_vcpu     = vcpu;
>> +
>> +     kvm_iodevice_init(&region->dev, &reg_desc->ops);
>> +
>> +     if (bpi) {
>> +             len = (bpi * nr_irqs) / 8;
>> +             if (offset_private)
>> +                     offset = (bpi * VGIC_NR_PRIVATE_IRQS) / 8;
>> +     } else {
>> +             len = reg_desc->len;
>> +     }
>> +
>> +     mutex_lock(&kvm->slots_lock);
>> +     ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +                                   region->base_addr + offset,
>> +                                   len - offset, &region->dev);
>> +     mutex_unlock(&kvm->slots_lock);
>> +
>> +     return ret;
>> +}
>> +
>> +int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>> +                            enum vgic_type type)
>> +{
>> +     struct vgic_io_device *regions;
>> +     struct vgic_register_region *reg_desc;
>> +     int nr_regions;
>> +     int nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +     int i;
>> +     int ret = 0;
>> +
>> +     switch (type) {
>> +     case VGIC_V2:
>> +             reg_desc = vgic_v2_dist_registers;
>> +             nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>> +             break;
>> +     default:
>> +             BUG_ON(1);
>> +     }
>> +
>> +     regions = kmalloc_array(nr_regions, sizeof(struct vgic_io_device),
>> +                             GFP_KERNEL);
>> +     if (!regions)
>> +             return -ENOMEM;
>> +
>> +     for (i = 0; i < nr_regions; i++) {
>> +             regions[i].base_addr    = dist_base_address;
>> +
>> +             ret = kvm_vgic_register_mmio_region(kvm, NULL, reg_desc,
>> +                                                 regions + i, nr_irqs,
>> +                                                 type == VGIC_V3);
>> +             if (ret)
>> +                     break;
>> +
>> +             reg_desc++;
>> +     }
>> +
>> +     if (ret) {
>> +             mutex_lock(&kvm->slots_lock);
>> +             for (i--; i >= 0; i--)
>> +                     kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +                                               &regions[i].dev);
>> +             mutex_unlock(&kvm->slots_lock);
>> +     } else {
>> +             kvm->arch.vgic.dist_iodevs = regions;
>> +     }
>> +
>> +     return ret;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.h b/virt/kvm/arm/vgic/vgic_mmio.h
>> new file mode 100644
>> index 0000000..cf2314c
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.h
>> @@ -0,0 +1,47 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * 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_ARM_VGIC_MMIO_H__
>> +#define __KVM_ARM_VGIC_MMIO_H__
>> +
>> +struct vgic_register_region {
>> +     int reg_offset;
>> +     int len;
>> +     int bits_per_irq;
>> +     struct kvm_io_device_ops ops;
>> +};
>> +
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(name, read_ops, write_ops, bpi) \
>> +     {.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
>> +      .ops.read = read_ops, .ops.write = write_ops}
>> +#define REGISTER_DESC_WITH_LENGTH(name, read_ops, write_ops, length) \
>> +     {.reg_offset = name, .bits_per_irq = 0, .len = length, \
>> +      .ops.read = read_ops, .ops.write = write_ops}
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +                    gpa_t addr, int len, void *val);
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +                    gpa_t addr, int len, const void *val);
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +                               struct vgic_register_region *reg_desc,
>> +                               struct vgic_io_device *region,
>> +                               int nr_irqs, bool offset_private);
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val);
>> +void write_mask64(u64 value, int offset, int len, void *val);
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val);
>> +u64 mask64(u64 origvalue, int offset, int len, const void *val);
>> +
>> +#endif
>> --
>> 2.7.3
>>
>>
>
> Thanks,
> -Christoffer

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

* Re: [RFC PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31  9:24     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:24 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:36AM +0000, Andre Przywara wrote:
> Userland can access the emulated GIC to save and restore its state
> for initialization or migration purposes.
> The kvm_io_bus API requires an absolute gpa, which does not fit the
> KVM_DEV_ARM_VGIC_GRP_DIST_REGS user API, that only provides relative
> offsets. So we explicitly iterate our register list to connect
> userland to the VGIC.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> ---
>  virt/kvm/arm/vgic/vgic.h      |  2 ++
>  virt/kvm/arm/vgic/vgic_mmio.c | 45 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 47 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 53730ba..a462e2b 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -25,6 +25,8 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>  void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			int offset, int len, void *val);
>  
>  #ifdef CONFIG_KVM_ARM_VGIC_V3
>  void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 26c46e7..e1fd17f 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -113,6 +113,51 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>  };
>  
> +/*
> + * Using kvm_io_bus_* to access GIC registers directly from userspace does
> + * not work, since we would need the absolute IPA address of the register
> + * in question, but the userland interface only provides relative offsets.
> + * So we provide our own dispatcher function for that purpose here.
> + */
> +static int vgic_mmio_access(struct kvm_vcpu *vcpu,
> +			    struct vgic_register_region *region, int nr_regions,
> +			    bool is_write, int offset, int len, void *val)
> +{

I suspect this is going to get rewored based on previous discussions
with the IO api...

> +	int i;
> +	struct vgic_io_device dev;
> +
> +	for (i = 0; i < nr_regions; i++) {
> +		int reg_size = region[i].len;
> +
> +		if (!reg_size)
> +			reg_size = (region[i].bits_per_irq * 1024) / 8;
> +
> +		if ((offset < region[i].reg_offset) ||
> +		    (offset + len > region[i].reg_offset + reg_size))
> +			continue;
> +
> +		dev.base_addr	= region[i].reg_offset;
> +		dev.redist_vcpu	= vcpu;
> +
> +		if (is_write)
> +			return region[i].ops.write(vcpu, &dev.dev,
> +						   offset, len, val);
> +		else
> +			return region[i].ops.read(vcpu, &dev.dev,
> +						  offset, len, val);
> +	}
> +
> +	return -ENODEV;
> +}
> +
> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			int offset, int len, void *val)
> +{
> +	return vgic_mmio_access(vcpu, vgic_v2_dist_registers,
> +				ARRAY_SIZE(vgic_v2_dist_registers),
> +				is_write, offset, len, val);
> +}
> +

this makes me wonder if the v2 region declarations and functions like
this should go in a separate file?  vgic/mmio-v2.c ?

>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  				  struct vgic_register_region *reg_desc,
>  				  struct vgic_io_device *region,
> -- 
> 2.7.3
> 

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

* [RFC PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface
@ 2016-03-31  9:24     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:36AM +0000, Andre Przywara wrote:
> Userland can access the emulated GIC to save and restore its state
> for initialization or migration purposes.
> The kvm_io_bus API requires an absolute gpa, which does not fit the
> KVM_DEV_ARM_VGIC_GRP_DIST_REGS user API, that only provides relative
> offsets. So we explicitly iterate our register list to connect
> userland to the VGIC.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> ---
>  virt/kvm/arm/vgic/vgic.h      |  2 ++
>  virt/kvm/arm/vgic/vgic_mmio.c | 45 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 47 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 53730ba..a462e2b 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -25,6 +25,8 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>  void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			int offset, int len, void *val);
>  
>  #ifdef CONFIG_KVM_ARM_VGIC_V3
>  void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 26c46e7..e1fd17f 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -113,6 +113,51 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>  };
>  
> +/*
> + * Using kvm_io_bus_* to access GIC registers directly from userspace does
> + * not work, since we would need the absolute IPA address of the register
> + * in question, but the userland interface only provides relative offsets.
> + * So we provide our own dispatcher function for that purpose here.
> + */
> +static int vgic_mmio_access(struct kvm_vcpu *vcpu,
> +			    struct vgic_register_region *region, int nr_regions,
> +			    bool is_write, int offset, int len, void *val)
> +{

I suspect this is going to get rewored based on previous discussions
with the IO api...

> +	int i;
> +	struct vgic_io_device dev;
> +
> +	for (i = 0; i < nr_regions; i++) {
> +		int reg_size = region[i].len;
> +
> +		if (!reg_size)
> +			reg_size = (region[i].bits_per_irq * 1024) / 8;
> +
> +		if ((offset < region[i].reg_offset) ||
> +		    (offset + len > region[i].reg_offset + reg_size))
> +			continue;
> +
> +		dev.base_addr	= region[i].reg_offset;
> +		dev.redist_vcpu	= vcpu;
> +
> +		if (is_write)
> +			return region[i].ops.write(vcpu, &dev.dev,
> +						   offset, len, val);
> +		else
> +			return region[i].ops.read(vcpu, &dev.dev,
> +						  offset, len, val);
> +	}
> +
> +	return -ENODEV;
> +}
> +
> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			int offset, int len, void *val)
> +{
> +	return vgic_mmio_access(vcpu, vgic_v2_dist_registers,
> +				ARRAY_SIZE(vgic_v2_dist_registers),
> +				is_write, offset, len, val);
> +}
> +

this makes me wonder if the v2 region declarations and functions like
this should go in a separate file?  vgic/mmio-v2.c ?

>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  				  struct vgic_register_region *reg_desc,
>  				  struct vgic_io_device *region,
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31  9:27     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:27 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:04:37AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.h      |  3 +++
>  virt/kvm/arm/vgic/vgic_mmio.c | 49 ++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 51 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index a462e2b..57aea8f 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -16,6 +16,9 @@
>  #ifndef __KVM_ARM_VGIC_NEW_H__
>  #define __KVM_ARM_VGIC_NEW_H__
>  
> +#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
> +#define IMPLEMENTER_ARM		0x43b
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index e1fd17f..e62366e 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -82,9 +82,56 @@ static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 value;
> +
> +	switch ((addr - iodev->base_addr) & ~3) {
> +	case 0x0:
> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
> +		break;
> +	case 0x4:
> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +		value = (value >> 5) - 1;
> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
> +		break;
> +	case 0x8:
> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	/*
> +	 * GICD_TYPER and GICD_IIDR are read-only, the upper three bytes of
> +	 * GICD_CTLR are reserved.
> +	 */
> +	if (addr - iodev->base_addr >= 1)
> +		return 0;
> +
> +	vcpu->kvm->arch.vgic.enabled = (*(u32 *)val) ? true : false;
> +	/* TODO: is there anything to trigger at this point? */

I guess we should actually check if the vgic is enabled in PATH 11, and
we should kick all VCPUs (or at least those with something pending) if
we went from disabled to enabled?

We should probably also check this in the sync function...

Or do we enforce this enabled bool somewhere else that I missed?

> +
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
> +		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> -- 
> 2.7.3
> 

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

* [RFC PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-03-31  9:27     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:37AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.h      |  3 +++
>  virt/kvm/arm/vgic/vgic_mmio.c | 49 ++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 51 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index a462e2b..57aea8f 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -16,6 +16,9 @@
>  #ifndef __KVM_ARM_VGIC_NEW_H__
>  #define __KVM_ARM_VGIC_NEW_H__
>  
> +#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
> +#define IMPLEMENTER_ARM		0x43b
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index e1fd17f..e62366e 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -82,9 +82,56 @@ static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 value;
> +
> +	switch ((addr - iodev->base_addr) & ~3) {
> +	case 0x0:
> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
> +		break;
> +	case 0x4:
> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +		value = (value >> 5) - 1;
> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
> +		break;
> +	case 0x8:
> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	/*
> +	 * GICD_TYPER and GICD_IIDR are read-only, the upper three bytes of
> +	 * GICD_CTLR are reserved.
> +	 */
> +	if (addr - iodev->base_addr >= 1)
> +		return 0;
> +
> +	vcpu->kvm->arch.vgic.enabled = (*(u32 *)val) ? true : false;
> +	/* TODO: is there anything to trigger at this point? */

I guess we should actually check if the vgic is enabled in PATH 11, and
we should kick all VCPUs (or at least those with something pending) if
we went from disabled to enabled?

We should probably also check this in the sync function...

Or do we enforce this enabled bool somewhere else that I missed?

> +
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
> +		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 15/45] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31  9:33     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:33 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:04:38AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 81 +++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 79 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index e62366e..0688a69 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -129,15 +129,92 @@ static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +/*
> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> + * of the enabled bit, so there is only one function for both here.
> + */
> +static int vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> +				 struct kvm_io_device *this,
> +				 gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->enabled)
> +			value |= (1U << i);
> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->enabled = true;
> +		vgic_queue_irq(vcpu->kvm, irq);

this makes me feel like we should rename this to vgic_queue_irq_unlock

> +	}
> +
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->enabled = false;
> +		/* TODO: Does the exit/entry code take care of "unqueuing"? */

yes it does, the sync calls prune_ap_list, which calls the Oracle, which
returns null if the IRQ is no longer enabled, so the prune function
removes the IRQ from the list.

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> -- 
> 2.7.3
> 

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

* [RFC PATCH 15/45] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-03-31  9:33     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:38AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 81 +++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 79 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index e62366e..0688a69 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -129,15 +129,92 @@ static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +/*
> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> + * of the enabled bit, so there is only one function for both here.
> + */
> +static int vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> +				 struct kvm_io_device *this,
> +				 gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->enabled)
> +			value |= (1U << i);
> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->enabled = true;
> +		vgic_queue_irq(vcpu->kvm, irq);

this makes me feel like we should rename this to vgic_queue_irq_unlock

> +	}
> +
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->enabled = false;
> +		/* TODO: Does the exit/entry code take care of "unqueuing"? */

yes it does, the sync calls prune_ap_list, which calls the Oracle, which
returns null if the IRQ is no longer enabled, so the prune function
removes the IRQ from the list.

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31  9:35     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:35 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:04:39AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 87 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 85 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 0688a69..8514f92 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -206,6 +206,89 @@ static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		if (irq->pending)
> +			value |= (1U << i);
> +		spin_unlock(&irq->irq_lock);

here there clearly is no need to take the lock (because a bool read is
atomic), but that should be explained in a one-line comment.

> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			irq->soft_pending = true;
> +
> +		vgic_queue_irq(vcpu->kvm, irq);
> +	}
> +
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		if (irq->config == VGIC_CONFIG_LEVEL) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		} else {
> +			irq->pending = false;
> +		}
> +		/* TODO: Does the exit/entry code take care of "unqueuing"? */

see previous patch comment

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -216,9 +299,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>  		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> -- 
> 2.7.3
> 

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

* [RFC PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
@ 2016-03-31  9:35     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:39AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 87 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 85 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 0688a69..8514f92 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -206,6 +206,89 @@ static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		if (irq->pending)
> +			value |= (1U << i);
> +		spin_unlock(&irq->irq_lock);

here there clearly is no need to take the lock (because a bool read is
atomic), but that should be explained in a one-line comment.

> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			irq->soft_pending = true;
> +
> +		vgic_queue_irq(vcpu->kvm, irq);
> +	}
> +
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		if (irq->config == VGIC_CONFIG_LEVEL) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		} else {
> +			irq->pending = false;
> +		}
> +		/* TODO: Does the exit/entry code take care of "unqueuing"? */

see previous patch comment

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -216,9 +299,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>  		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31  9:47     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:47 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the functionality for syncing IRQs between our emulation
> and the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h     |   4 +
>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h    |   4 +
>  4 files changed, 373 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index f32b284..986f23f 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>  
> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 0bf6f27..1cec423 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -14,11 +14,172 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> +#include <linux/irqchip/arm-gic.h>
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
>  
>  #include "vgic.h"
>  
> +/*
> + * Call this function to convert a u64 value to an unsigned long * bitmask
> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> + *
> + * Warning: Calling this function may modify *val.
> + */
> +static unsigned long *u64_to_bitmask(u64 *val)
> +{
> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> +	*val = (*val >> 32) | (*val << 32);
> +#endif
> +	return (unsigned long *)val;
> +}
> +
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> +		u64 eisr = cpuif->vgic_eisr;
> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> +		int lr;
> +
> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> +			struct vgic_irq *irq;
> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> +
> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +	}
> +
> +	/* check and disable underflow maintenance IRQ */
> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> +
> +	/*
> +	 * In the next iterations of the vcpu loop, if we sync the
> +	 * vgic state after flushing it, but before entering the guest
> +	 * (this happens for pending signals and vmid rollovers), then
> +	 * make sure we don't pick up any old maintenance interrupts
> +	 * here.
> +	 */
> +	cpuif->vgic_eisr = 0;
> +}
> +
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> +}
> +
> +/*
> + * transfer the content of the LRs back into the corresponding ap_list:
> + * - active bit is transferred as is
> + * - pending bit is
> + *   - transferred as is in case of edge sensitive IRQs
> + *   - set to the line-level (resample time) for level sensitive IRQs
> + */
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int lr;
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u32 val = cpuif->vgic_lr[lr];
> +		u32 intid = val & GICH_LR_VIRTUALID;
> +		struct vgic_irq *irq;
> +
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & GICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (intid < VGIC_NR_SGIS) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level IRQs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & GICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/*
> + * Populates the particular LR with the state of a given IRQ:
> + * - for an edge sensitive IRQ the pending state is reset in the struct
> + * - for a level sensitive IRQ the pending state value is unchanged;
> + *   it will be resampled on deactivation
> + *
> + * If irq is not NULL, the irq_lock must be hold already by the caller.
> + * If irq is NULL, the respective LR gets cleared.
> + */
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 val;
> +
> +	if (!irq) {
> +		val = 0;
> +		goto out;
> +	}
> +
> +	val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= GICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (irq->intid < VGIC_NR_SGIS) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= GICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= GICH_LR_HW;
> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= GICH_LR_EOI;
> +	}

shouldn't we start writing the priority here (and in the GICv3 version)?

(which has the fun consequence of having to compare priorities against
the virtual priority filter in PATCH 11).

> +
> +out:
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
> +}
> +
>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 29c753e..90a85bf 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>  	return 0;
>  }
> +
> +/**
> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> + *
> + * @vcpu: The VCPU pointer
> + *
> + * Go over the list of "interesting" interrupts, and prune those that we
> + * won't have to consider in the near future.
> + */
> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq, *tmp;
> +
> +retry:
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		BUG_ON(vcpu != irq->vcpu);
> +
> +		target_vcpu = vgic_target_oracle(irq);
> +
> +		if (!target_vcpu) {
> +			/*
> +			 * We don't need to process this interrupt any
> +			 * further, move it off the list.
> +			 */
> +			list_del_init(&irq->ap_list);
> +			irq->vcpu = NULL;
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		if (target_vcpu == vcpu) {
> +			/* We're on the right CPU */
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		/* This interrupt looks like it has to be migrated. */
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +		/*
> +		 * Ensure locking order by always locking the smallest
> +		 * ID first.
> +		 */
> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> +			vcpuA = vcpu;
> +			vcpuB = target_vcpu;
> +		} else {
> +			vcpuA = target_vcpu;
> +			vcpuB = vcpu;
> +		}
> +
> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * If the affinity has been preserved, move the
> +		 * interrupt around. Otherwise, it means things have
> +		 * changed while the interrupt was unlocked, and we
> +		 * need to replay this.
> +		 *
> +		 * In all cases, we cannot trust the list not to have
> +		 * changed, so we restart from the beginning.
> +		 */
> +		if (target_vcpu == vgic_target_oracle(irq)) {
> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> +
> +			list_del_init(&irq->ap_list);
> +			irq->vcpu = target_vcpu;
> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		goto retry;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +}
> +
> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_process_maintenance(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_fold_lr_state(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +/*
> + * Requires the ap_lock to be held.
> + * If irq is not NULL, requires the IRQ lock to be held as well.
> + * If irq is NULL, the list register gets cleared.
> + */
> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> +				    struct vgic_irq *irq, int lr)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_populate_lr(vcpu, irq, lr);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_set_underflow(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		/* GICv2 SGIs can count for more than one... */
> +		if (irq->intid < VGIC_NR_SGIS && irq->source)
> +			count += hweight8(irq->source);
> +		else
> +			count++;
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return count;
> +}
> +
> +/* requires the vcpu ap_lock to be held */
> +static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
> +		    irq->intid < VGIC_NR_SGIS) {
> +			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
> +				vgic_populate_lr(vcpu, irq, count++);
> +		} else {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		}
> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == vcpu->arch.vgic_cpu.nr_lr)
> +			break;
> +	}
> +
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
> +		vgic_populate_lr(vcpu, NULL, count);
> +}
> +
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_fold_lr_state(vcpu);
> +	vgic_prune_ap_list(vcpu);
> +}
> +
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	vgic_populate_lrs(vcpu);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index b2faf00..95ef3cf 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -21,5 +21,9 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>  
>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  
>  #endif
> -- 
> 2.7.3
> 

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

* [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
@ 2016-03-31  9:47     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the functionality for syncing IRQs between our emulation
> and the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h     |   4 +
>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h    |   4 +
>  4 files changed, 373 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index f32b284..986f23f 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>  
> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 0bf6f27..1cec423 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -14,11 +14,172 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> +#include <linux/irqchip/arm-gic.h>
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
>  
>  #include "vgic.h"
>  
> +/*
> + * Call this function to convert a u64 value to an unsigned long * bitmask
> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> + *
> + * Warning: Calling this function may modify *val.
> + */
> +static unsigned long *u64_to_bitmask(u64 *val)
> +{
> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> +	*val = (*val >> 32) | (*val << 32);
> +#endif
> +	return (unsigned long *)val;
> +}
> +
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> +		u64 eisr = cpuif->vgic_eisr;
> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> +		int lr;
> +
> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> +			struct vgic_irq *irq;
> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> +
> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +	}
> +
> +	/* check and disable underflow maintenance IRQ */
> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> +
> +	/*
> +	 * In the next iterations of the vcpu loop, if we sync the
> +	 * vgic state after flushing it, but before entering the guest
> +	 * (this happens for pending signals and vmid rollovers), then
> +	 * make sure we don't pick up any old maintenance interrupts
> +	 * here.
> +	 */
> +	cpuif->vgic_eisr = 0;
> +}
> +
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> +}
> +
> +/*
> + * transfer the content of the LRs back into the corresponding ap_list:
> + * - active bit is transferred as is
> + * - pending bit is
> + *   - transferred as is in case of edge sensitive IRQs
> + *   - set to the line-level (resample time) for level sensitive IRQs
> + */
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int lr;
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u32 val = cpuif->vgic_lr[lr];
> +		u32 intid = val & GICH_LR_VIRTUALID;
> +		struct vgic_irq *irq;
> +
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & GICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (intid < VGIC_NR_SGIS) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level IRQs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & GICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/*
> + * Populates the particular LR with the state of a given IRQ:
> + * - for an edge sensitive IRQ the pending state is reset in the struct
> + * - for a level sensitive IRQ the pending state value is unchanged;
> + *   it will be resampled on deactivation
> + *
> + * If irq is not NULL, the irq_lock must be hold already by the caller.
> + * If irq is NULL, the respective LR gets cleared.
> + */
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 val;
> +
> +	if (!irq) {
> +		val = 0;
> +		goto out;
> +	}
> +
> +	val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= GICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (irq->intid < VGIC_NR_SGIS) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= GICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= GICH_LR_HW;
> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= GICH_LR_EOI;
> +	}

shouldn't we start writing the priority here (and in the GICv3 version)?

(which has the fun consequence of having to compare priorities against
the virtual priority filter in PATCH 11).

> +
> +out:
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
> +}
> +
>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 29c753e..90a85bf 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>  	return 0;
>  }
> +
> +/**
> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> + *
> + * @vcpu: The VCPU pointer
> + *
> + * Go over the list of "interesting" interrupts, and prune those that we
> + * won't have to consider in the near future.
> + */
> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq, *tmp;
> +
> +retry:
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		BUG_ON(vcpu != irq->vcpu);
> +
> +		target_vcpu = vgic_target_oracle(irq);
> +
> +		if (!target_vcpu) {
> +			/*
> +			 * We don't need to process this interrupt any
> +			 * further, move it off the list.
> +			 */
> +			list_del_init(&irq->ap_list);
> +			irq->vcpu = NULL;
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		if (target_vcpu == vcpu) {
> +			/* We're on the right CPU */
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		/* This interrupt looks like it has to be migrated. */
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +		/*
> +		 * Ensure locking order by always locking the smallest
> +		 * ID first.
> +		 */
> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> +			vcpuA = vcpu;
> +			vcpuB = target_vcpu;
> +		} else {
> +			vcpuA = target_vcpu;
> +			vcpuB = vcpu;
> +		}
> +
> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * If the affinity has been preserved, move the
> +		 * interrupt around. Otherwise, it means things have
> +		 * changed while the interrupt was unlocked, and we
> +		 * need to replay this.
> +		 *
> +		 * In all cases, we cannot trust the list not to have
> +		 * changed, so we restart from the beginning.
> +		 */
> +		if (target_vcpu == vgic_target_oracle(irq)) {
> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> +
> +			list_del_init(&irq->ap_list);
> +			irq->vcpu = target_vcpu;
> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		goto retry;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +}
> +
> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_process_maintenance(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_fold_lr_state(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +/*
> + * Requires the ap_lock to be held.
> + * If irq is not NULL, requires the IRQ lock to be held as well.
> + * If irq is NULL, the list register gets cleared.
> + */
> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> +				    struct vgic_irq *irq, int lr)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_populate_lr(vcpu, irq, lr);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_set_underflow(vcpu);
> +	else
> +		WARN(1, "GICv3 Not Implemented\n");
> +}
> +
> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		/* GICv2 SGIs can count for more than one... */
> +		if (irq->intid < VGIC_NR_SGIS && irq->source)
> +			count += hweight8(irq->source);
> +		else
> +			count++;
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return count;
> +}
> +
> +/* requires the vcpu ap_lock to be held */
> +static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
> +		    irq->intid < VGIC_NR_SGIS) {
> +			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
> +				vgic_populate_lr(vcpu, irq, count++);
> +		} else {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		}
> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == vcpu->arch.vgic_cpu.nr_lr)
> +			break;
> +	}
> +
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
> +		vgic_populate_lr(vcpu, NULL, count);
> +}
> +
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_fold_lr_state(vcpu);
> +	vgic_prune_ap_list(vcpu);
> +}
> +
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	vgic_populate_lrs(vcpu);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index b2faf00..95ef3cf 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -21,5 +21,9 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>  
>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  
>  #endif
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 17/45] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31  9:50     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:50 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:40AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 46 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 45 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 8514f92..788e186 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -289,6 +289,50 @@ static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		((u8 *)val)[i] = irq->priority;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->priority = ((u8 *)val)[i];
> +		spin_unlock(&irq->irq_lock);

if we add the priority check in PATCH 11 you have to kick the vcpu here
irq->vcpu is set.  (and possibly even without a change to PATCH 11 in
case the VCPU is running with a bund of now lower-priority interrupts in
the LRs).

> +	}
> +
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -307,7 +351,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> -- 
> 2.7.3
> 

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

* [RFC PATCH 17/45] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
@ 2016-03-31  9:50     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:40AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 46 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 45 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 8514f92..788e186 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -289,6 +289,50 @@ static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		((u8 *)val)[i] = irq->priority;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->priority = ((u8 *)val)[i];
> +		spin_unlock(&irq->irq_lock);

if we add the priority check in PATCH 11 you have to kick the vcpu here
irq->vcpu is set.  (and possibly even without a change to PATCH 11 in
case the VCPU is running with a bund of now lower-priority interrupts in
the LRs).

> +	}
> +
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -307,7 +351,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 18/45] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31  9:58     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:58 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:04:41AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 81 +++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 79 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 788e186..bfc530c 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -289,6 +289,83 @@ static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> +				 struct kvm_io_device *this,
> +				 gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		if (irq->active)
> +			value |= (1U << i);
> +		spin_unlock(&irq->irq_lock);

you don't need the spinlock here (for the same reason you didn't grab it
in the last patch, consistency above all on this matter, please).

> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->active = false;
> +		/* TODO: Anything more to do? Does flush/sync cover this? */

so prune will remove this from the AP list if it's no longer
pending/enabled as well.

the question is what to do if the vcpu for this irq is running and the
LR there has the active bit set, then we'll overwrite this change when
we fold the LR state back into the vgic_irq struct.

since I expect this to be extremely rare, one option is to force
irq->vcpu to exit (if non-null) and then do you thing here after you've
confirm it has exited while holding some lock preventing it from
re-entering again.  Slightly crazy.

The alternative is to put a big fat comment nothing that this is
non-supported bad race, and wait until someone submits a bug report
relating to this...

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->active = true;
> +		/* TODO: Anything more to do? Does flush/sync cover this? */

you need to add it to the ap_list of irq->target_vcpu if irq->vcpu is
not already set.

an alternative is to expand the queue function to handle the active
case, but I'm not sure which one is cleaner.  I think we have to try it
to be able to tell, but my gut feeling is that implementing it here is
better, because it's a one-off.

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
>  static int vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
>  				   struct kvm_io_device *this,
>  				   gpa_t addr, int len, void *val)
> @@ -347,9 +424,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>  		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> -- 
> 2.7.3
> 

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

* [RFC PATCH 18/45] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
@ 2016-03-31  9:58     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31  9:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:41AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 81 +++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 79 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 788e186..bfc530c 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -289,6 +289,83 @@ static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> +				 struct kvm_io_device *this,
> +				 gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		if (irq->active)
> +			value |= (1U << i);
> +		spin_unlock(&irq->irq_lock);

you don't need the spinlock here (for the same reason you didn't grab it
in the last patch, consistency above all on this matter, please).

> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->active = false;
> +		/* TODO: Anything more to do? Does flush/sync cover this? */

so prune will remove this from the AP list if it's no longer
pending/enabled as well.

the question is what to do if the vcpu for this irq is running and the
LR there has the active bit set, then we'll overwrite this change when
we fold the LR state back into the vgic_irq struct.

since I expect this to be extremely rare, one option is to force
irq->vcpu to exit (if non-null) and then do you thing here after you've
confirm it has exited while holding some lock preventing it from
re-entering again.  Slightly crazy.

The alternative is to put a big fat comment nothing that this is
non-supported bad race, and wait until someone submits a bug report
relating to this...

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 8;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for_each_set_bit(i, val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->active = true;
> +		/* TODO: Anything more to do? Does flush/sync cover this? */

you need to add it to the ap_list of irq->target_vcpu if irq->vcpu is
not already set.

an alternative is to expand the queue function to handle the active
case, but I'm not sure which one is cleaner.  I think we have to try it
to be able to tell, but my gut feeling is that implementing it here is
better, because it's a one-off.

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
>  static int vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
>  				   struct kvm_io_device *this,
>  				   gpa_t addr, int len, void *val)
> @@ -347,9 +424,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>  		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 19/45] KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31 10:07     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 10:07 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:04:42AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 63 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 62 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index bfc530c..76657ce 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -410,6 +410,67 @@ static int vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_config(struct kvm_vcpu *vcpu,
> +				 struct kvm_io_device *this,
> +				 gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 4;
> +	u32 value = 0;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for (i = 0; i < len * 4; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			value |= (2U << (i * 2));
> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 4;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for (i = 0; i < len * 4; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (intid + i < 16)
> +			continue;
> +
> +		/*
> +		 * The spec says that interrupts must be disabled before
> +		 * changing the configuration to avoid UNDEFINED behaviour.
> +		 * Is this sufficient in our case? Do we quickly enough remove
> +		 * the IRQ from the ap_list to safely do the config change?

I don't understand the question about 'quickly enough' here.

> +		 * Will even a disabled interrupt in an ap_list cause us
> +		 * headaches if we change the configuration?
> +		 */

I don't think there's any particular problem here, except for my
comments below:

(there may be some super weirdness if a VCPU is running with some bits
of this IRQ in a LR while changing it, but I think we can ignore this
case for now - or we can do like with the active state and force an
exit).

> +		spin_lock(&irq->irq_lock);
> +		if (test_bit(i * 2 + 1, val))
> +			irq->config = VGIC_CONFIG_EDGE;
> +		else
> +			irq->config = VGIC_CONFIG_LEVEL;

I think here you have to sync pending to level | soft_pending, that's a
rule we enforce for level triggered interrupts.

> +		spin_unlock(&irq->irq_lock);
> +	}
> +
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -432,7 +493,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> -- 
> 2.7.3
> 

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

* [RFC PATCH 19/45] KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
@ 2016-03-31 10:07     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 10:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:42AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 63 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 62 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index bfc530c..76657ce 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -410,6 +410,67 @@ static int vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_config(struct kvm_vcpu *vcpu,
> +				 struct kvm_io_device *this,
> +				 gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 4;
> +	u32 value = 0;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for (i = 0; i < len * 4; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			value |= (2U << (i * 2));
> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr) * 4;
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for (i = 0; i < len * 4; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (intid + i < 16)
> +			continue;
> +
> +		/*
> +		 * The spec says that interrupts must be disabled before
> +		 * changing the configuration to avoid UNDEFINED behaviour.
> +		 * Is this sufficient in our case? Do we quickly enough remove
> +		 * the IRQ from the ap_list to safely do the config change?

I don't understand the question about 'quickly enough' here.

> +		 * Will even a disabled interrupt in an ap_list cause us
> +		 * headaches if we change the configuration?
> +		 */

I don't think there's any particular problem here, except for my
comments below:

(there may be some super weirdness if a VCPU is running with some bits
of this IRQ in a LR while changing it, but I think we can ignore this
case for now - or we can do like with the active state and force an
exit).

> +		spin_lock(&irq->irq_lock);
> +		if (test_bit(i * 2 + 1, val))
> +			irq->config = VGIC_CONFIG_EDGE;
> +		else
> +			irq->config = VGIC_CONFIG_LEVEL;

I think here you have to sync pending to level | soft_pending, that's a
rule we enforce for level triggered interrupts.

> +		spin_unlock(&irq->irq_lock);
> +	}
> +
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -432,7 +493,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31 11:31     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 11:31 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:43AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 42 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 76657ce..cde153f 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
> +				 struct kvm_io_device *this,
> +				 gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		((u8 *)val)[i] = irq->targets;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	/* GICD_ITARGETSR[0-7] are read-only */
> +	if (intid < VGIC_NR_PRIVATE_IRQS)
> +		return 0;
> +
> +	for (i = 0; i < len; i++)
> +		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
> +					    ((u8 *)val)[i]);
> +
> +	return 0;
> +}
> +

these functions are v2 specific but are in a generic file and are not
named anything specific to v2?

>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -491,7 +532,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +		vgic_mmio_read_target, vgic_mmio_write_target, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> -- 
> 2.7.3
> 
> --
> 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] 276+ messages in thread

* [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
@ 2016-03-31 11:31     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:43AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 42 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 76657ce..cde153f 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
> +				 struct kvm_io_device *this,
> +				 gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	if (iodev->redist_vcpu)
> +		vcpu = iodev->redist_vcpu;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		((u8 *)val)[i] = irq->targets;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	/* GICD_ITARGETSR[0-7] are read-only */
> +	if (intid < VGIC_NR_PRIVATE_IRQS)
> +		return 0;
> +
> +	for (i = 0; i < len; i++)
> +		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
> +					    ((u8 *)val)[i]);
> +
> +	return 0;
> +}
> +

these functions are v2 specific but are in a generic file and are not
named anything specific to v2?

>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -491,7 +532,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> +		vgic_mmio_read_target, vgic_mmio_write_target, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> -- 
> 2.7.3
> 
> --
> 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] 276+ messages in thread

* Re: [RFC PATCH 21/45] KVM: arm/arm64: vgic-new: Add SGIR register handler
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31 11:35     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 11:35 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:44AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 46 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 45 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index cde153f..a49726f 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -512,6 +512,50 @@ static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
> +				struct kvm_io_device *this,
> +				gpa_t addr, int len, const void *val)
> +{
> +	int nr_vcpus = atomic_read(&source_vcpu->kvm->online_vcpus);
> +	u32 value = *(u32 *)val;
> +	int intid = value & 0xf;
> +	int targets = (value >> 16) & 0xff;
> +	int mode = (value >> 24) & 0x03;
> +	int c;
> +	struct kvm_vcpu *vcpu;
> +
> +	switch (mode) {
> +	case 0x0:		/* as specified by targets */
> +		break;
> +	case 0x1:
> +		targets = (1U << nr_vcpus) - 1;			/* all, ... */
> +		targets &= ~(1U << source_vcpu->vcpu_id);	/* but self */
> +		break;
> +	case 0x2:		/* this very vCPU only */
> +		targets = (1U << source_vcpu->vcpu_id);
> +		break;
> +	case 0x3:		/* reserved */

should we not avoid generating any SGIs in this case?

> +		break;
> +	}
> +
> +	kvm_for_each_vcpu(c, vcpu, source_vcpu->kvm) {
> +		struct vgic_irq *irq;
> +
> +		if (!(targets & (1U << c)))
> +			continue;
> +
> +		irq = vgic_get_irq(source_vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +		irq->source |= 1U << source_vcpu->vcpu_id;
> +
> +		vgic_queue_irq(source_vcpu->kvm, irq);
> +	}
> +
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -536,7 +580,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
> +		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> -- 
> 2.7.3
> 

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

* [RFC PATCH 21/45] KVM: arm/arm64: vgic-new: Add SGIR register handler
@ 2016-03-31 11:35     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:44AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 46 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 45 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index cde153f..a49726f 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -512,6 +512,50 @@ static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
> +				struct kvm_io_device *this,
> +				gpa_t addr, int len, const void *val)
> +{
> +	int nr_vcpus = atomic_read(&source_vcpu->kvm->online_vcpus);
> +	u32 value = *(u32 *)val;
> +	int intid = value & 0xf;
> +	int targets = (value >> 16) & 0xff;
> +	int mode = (value >> 24) & 0x03;
> +	int c;
> +	struct kvm_vcpu *vcpu;
> +
> +	switch (mode) {
> +	case 0x0:		/* as specified by targets */
> +		break;
> +	case 0x1:
> +		targets = (1U << nr_vcpus) - 1;			/* all, ... */
> +		targets &= ~(1U << source_vcpu->vcpu_id);	/* but self */
> +		break;
> +	case 0x2:		/* this very vCPU only */
> +		targets = (1U << source_vcpu->vcpu_id);
> +		break;
> +	case 0x3:		/* reserved */

should we not avoid generating any SGIs in this case?

> +		break;
> +	}
> +
> +	kvm_for_each_vcpu(c, vcpu, source_vcpu->kvm) {
> +		struct vgic_irq *irq;
> +
> +		if (!(targets & (1U << c)))
> +			continue;
> +
> +		irq = vgic_get_irq(source_vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +		irq->source |= 1U << source_vcpu->vcpu_id;
> +
> +		vgic_queue_irq(source_vcpu->kvm, irq);
> +	}
> +
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -536,7 +580,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
> +		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 22/45] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31 11:37     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 11:37 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:45AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> 
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 79 ++++++++++++++++++++++++++++++++-----------
>  1 file changed, 59 insertions(+), 20 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index a49726f..2ab8961 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -64,24 +64,6 @@ int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>  	return 0;
>  }
>  
> -static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
> -			      struct kvm_io_device *this,
> -			      gpa_t addr, int len, void *val)
> -{
> -	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
> -		vcpu->vcpu_id, (unsigned long long)addr);
> -	return 0;
> -}
> -
> -static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
> -			       struct kvm_io_device *this,
> -			       gpa_t addr, int len, const void *val)
> -{
> -	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
> -		vcpu->vcpu_id, (unsigned long long)addr);
> -	return 0;
> -}
> -
>  static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>  				  struct kvm_io_device *this,
>  				  gpa_t addr, int len, void *val)
> @@ -556,6 +538,63 @@ static int vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		((u8 *)val)[i] = irq->source;
> +		spin_unlock(&irq->irq_lock);

you don't need the spinlock here

> +	}
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->source &= ~((u8 *)val)[i];

don't you also need to check if source == 0 and lower pending in this
case?

> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->source |= ((u8 *)val)[i];

don't you need to set pending and queue in this case?

> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -582,9 +621,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>  		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
> +		vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
> +		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>  };
>  
>  /*
> -- 
> 2.7.3
> 

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

* [RFC PATCH 22/45] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
@ 2016-03-31 11:37     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:45AM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> 
> ---
>  virt/kvm/arm/vgic/vgic_mmio.c | 79 ++++++++++++++++++++++++++++++++-----------
>  1 file changed, 59 insertions(+), 20 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index a49726f..2ab8961 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -64,24 +64,6 @@ int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>  	return 0;
>  }
>  
> -static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
> -			      struct kvm_io_device *this,
> -			      gpa_t addr, int len, void *val)
> -{
> -	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
> -		vcpu->vcpu_id, (unsigned long long)addr);
> -	return 0;
> -}
> -
> -static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
> -			       struct kvm_io_device *this,
> -			       gpa_t addr, int len, const void *val)
> -{
> -	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
> -		vcpu->vcpu_id, (unsigned long long)addr);
> -	return 0;
> -}
> -
>  static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>  				  struct kvm_io_device *this,
>  				  gpa_t addr, int len, void *val)
> @@ -556,6 +538,63 @@ static int vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
>  	return 0;
>  }
>  
> +static int vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		((u8 *)val)[i] = irq->source;
> +		spin_unlock(&irq->irq_lock);

you don't need the spinlock here

> +	}
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->source &= ~((u8 *)val)[i];

don't you also need to check if source == 0 and lower pending in this
case?

> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 intid = (addr - iodev->base_addr);
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->source |= ((u8 *)val)[i];

don't you need to set pending and queue in this case?

> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return 0;
> +}
> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -582,9 +621,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>  		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
> +		vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
> +		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>  };
>  
>  /*
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31 11:48     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 11:48 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:46AM +0000, Andre Przywara wrote:
> Describe the GICv3 distributor and redistributor registers in our
> structure. This adds a special macro to deal with the split of
> SGI/PPI in the redistributor and SPIs in the distributor, which
> allows us to reuse the existing GICv2 handlers for those registers
> which are compatible.
> Also we register the separate MMIO page for the redistributor
> registers dealing with private interrupts.
> GICv3 specific registers are only implemented as stubs at this time.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.h      |  16 +++
>  virt/kvm/arm/vgic/vgic_mmio.c | 246 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 262 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 57aea8f..4b8952a 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -37,6 +37,10 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
>  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			int offset, int len, void *val);
> +int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			  int offset, int len, void *val);
>  #else
>  static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
>  					       u64 mpidr)
> @@ -59,6 +63,18 @@ static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
>  static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>  {
>  }
> +
> +static inline int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> +				      int offset, int len, void *val)
> +{
> +	return -ENXIO;
> +}
> +
> +static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
> +					int offset, int len, void *val)
> +{
> +	return -ENXIO;
> +}
>  #endif
>  
>  #endif
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 2ab8961..2d10c06 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -17,6 +17,8 @@
>  #include <kvm/vgic/vgic.h>
>  #include <linux/bitops.h>
>  #include <linux/irqchip/arm-gic.h>
> +#include <linux/irqchip/arm-gic-v3.h>
> +#include <asm/kvm_emulate.h>
>  
>  #include "vgic.h"
>  #include "vgic_mmio.h"
> @@ -595,6 +597,105 @@ static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +/*****************************/
> +/* GICv3 emulation functions */
> +/*****************************/
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +
> +static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_read_v3r_misc(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, void *val)
> +{
> +	/* TODO: implement for ITS support */
> +	return vgic_mmio_read_raz(vcpu, this, addr, len, val);
> +}
> +
> +static int vgic_mmio_write_v3r_misc(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	/* TODO: implement for ITS support */
> +	return vgic_mmio_write_wi(vcpu, this, addr, len, val);
> +}
> +
> +static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, void *val)
> +{
> +	return 0;
> +}
> +
> +static int vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_read_v3r_propbase(struct kvm_vcpu *vcpu,
> +				       struct kvm_io_device *this,
> +				       gpa_t addr, int len, void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_v3r_propbase(struct kvm_vcpu *vcpu,
> +				        struct kvm_io_device *this,
> +				        gpa_t addr, int len, const void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_read_v3r_pendbase(struct kvm_vcpu *vcpu,
> +				       struct kvm_io_device *this,
> +				       gpa_t addr, int len, void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_v3r_pendbase(struct kvm_vcpu *vcpu,
> +				        struct kvm_io_device *this,
> +				        gpa_t addr, int len, const void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +#endif
> +
> +/*
> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
> + * redistributors, while SPIs are covered by registers in the distributor
> + * block. Trying to set private IRQs in this block gets ignored.
> + * We take some special care here to fix the calculation of the register
> + * offset.
> + */
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(name, read_ops, write_ops, bpi) \
> +	{.reg_offset = name, .bits_per_irq = 0, \
> +	 .len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
> +	 .ops.read = vgic_mmio_read_raz, .ops.write = vgic_mmio_write_wi, }, \
> +	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
> +	 .ops.read = read_ops, .ops.write = write_ops, }

why do we have two regions with the same offset and why does the one
that actually implements a handler have length 0 ?

> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -626,6 +727,73 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>  };
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +struct vgic_register_region vgic_v3_dist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> +		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +};
> +
> +struct vgic_register_region vgic_v3_redist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
> +		vgic_mmio_read_v3r_misc, vgic_mmio_write_v3r_misc, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
> +		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
> +		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
> +		vgic_mmio_read_v3r_propbase, vgic_mmio_write_v3r_propbase, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
> +		vgic_mmio_read_v3r_pendbase, vgic_mmio_write_v3r_pendbase, 8),
> +};
> +
> +struct vgic_register_region vgic_v3_private_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +};
> +#endif
> +
>  /*
>   * Using kvm_io_bus_* to access GIC registers directly from userspace does
>   * not work, since we would need the absolute IPA address of the register
> @@ -671,6 +839,24 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>  				is_write, offset, len, val);
>  }
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			int offset, int len, void *val)
> +{
> +	return vgic_mmio_access(vcpu, vgic_v3_dist_registers,
> +				ARRAY_SIZE(vgic_v3_dist_registers),
> +				is_write, offset, len, val);
> +}
> +
> +int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			  int offset, int len, void *val)
> +{
> +	return vgic_mmio_access(vcpu, vgic_v3_redist_registers,
> +				ARRAY_SIZE(vgic_v3_redist_registers),
> +				is_write, offset, len, val);
> +}
> +#endif
> +
>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  				  struct vgic_register_region *reg_desc,
>  				  struct vgic_io_device *region,
> @@ -717,6 +903,12 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>  		reg_desc = vgic_v2_dist_registers;
>  		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>  		break;
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +	case VGIC_V3:
> +		reg_desc = vgic_v3_dist_registers;
> +		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
> +		break;
> +#endif
>  	default:
>  		BUG_ON(1);
>  	}
> @@ -750,3 +942,57 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>  
>  	return ret;
>  }
> +
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
> +{
> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
> +	int nr_regions = ARRAY_SIZE(vgic_v3_redist_registers) +
> +			 ARRAY_SIZE(vgic_v3_private_registers);
> +	struct kvm_vcpu *vcpu;
> +	struct vgic_io_device *regions, *region;
> +	int c, i, ret = 0;
> +
> +	regions = kmalloc(sizeof(struct vgic_io_device) * nr_regions * nr_vcpus,
> +			  GFP_KERNEL);
> +	if (!regions)
> +		return -ENOMEM;
> +
> +	kvm_for_each_vcpu(c, vcpu, kvm) {
> +		region = &regions[c * nr_regions];
> +		for (i = 0; i < ARRAY_SIZE(vgic_v3_redist_registers); i++) {
> +			region->base_addr = redist_base_address;
> +			region->base_addr += c * 2 * SZ_64K;
> +
> +			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
> +						vgic_v3_redist_registers + i,
> +						region, VGIC_NR_PRIVATE_IRQS,
> +						false);
> +			if (ret)
> +				break;
> +			region++;
> +		}
> +		if (ret)
> +			break;
> +
> +		for (i = 0; i < ARRAY_SIZE(vgic_v3_private_registers); i++) {
> +			region->base_addr = redist_base_address;
> +			region->base_addr += c * 2 * SZ_64K + SZ_64K;
> +			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
> +						vgic_v3_private_registers + i,
> +						region, VGIC_NR_PRIVATE_IRQS,
> +						false);
> +			if (ret)
> +				break;
> +			region++;
> +		}
> +		if (ret)
> +			break;
> +	}
> +
> +	if (!ret)
> +		kvm->arch.vgic.redist_iodevs = regions;
> +
> +	return ret;

I'm not going to review all this in detail until we've figured out the
general approach to the IO bus stuff.

> +}
> +#endif
> -- 
> 2.7.3
> 
> --
> 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] 276+ messages in thread

* [RFC PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
@ 2016-03-31 11:48     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 11:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:46AM +0000, Andre Przywara wrote:
> Describe the GICv3 distributor and redistributor registers in our
> structure. This adds a special macro to deal with the split of
> SGI/PPI in the redistributor and SPIs in the distributor, which
> allows us to reuse the existing GICv2 handlers for those registers
> which are compatible.
> Also we register the separate MMIO page for the redistributor
> registers dealing with private interrupts.
> GICv3 specific registers are only implemented as stubs at this time.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.h      |  16 +++
>  virt/kvm/arm/vgic/vgic_mmio.c | 246 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 262 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 57aea8f..4b8952a 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -37,6 +37,10 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
>  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			int offset, int len, void *val);
> +int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			  int offset, int len, void *val);
>  #else
>  static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
>  					       u64 mpidr)
> @@ -59,6 +63,18 @@ static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
>  static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>  {
>  }
> +
> +static inline int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> +				      int offset, int len, void *val)
> +{
> +	return -ENXIO;
> +}
> +
> +static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
> +					int offset, int len, void *val)
> +{
> +	return -ENXIO;
> +}
>  #endif
>  
>  #endif
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 2ab8961..2d10c06 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -17,6 +17,8 @@
>  #include <kvm/vgic/vgic.h>
>  #include <linux/bitops.h>
>  #include <linux/irqchip/arm-gic.h>
> +#include <linux/irqchip/arm-gic-v3.h>
> +#include <asm/kvm_emulate.h>
>  
>  #include "vgic.h"
>  #include "vgic_mmio.h"
> @@ -595,6 +597,105 @@ static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +/*****************************/
> +/* GICv3 emulation functions */
> +/*****************************/
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +
> +static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
> +				  struct kvm_io_device *this,
> +				  gpa_t addr, int len, void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, const void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_read_v3r_misc(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, void *val)
> +{
> +	/* TODO: implement for ITS support */
> +	return vgic_mmio_read_raz(vcpu, this, addr, len, val);
> +}
> +
> +static int vgic_mmio_write_v3r_misc(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, const void *val)
> +{
> +	/* TODO: implement for ITS support */
> +	return vgic_mmio_write_wi(vcpu, this, addr, len, val);
> +}
> +
> +static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
> +				   struct kvm_io_device *this,
> +				   gpa_t addr, int len, void *val)
> +{
> +	return 0;
> +}
> +
> +static int vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
> +				    struct kvm_io_device *this,
> +				    gpa_t addr, int len, void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_read_v3r_propbase(struct kvm_vcpu *vcpu,
> +				       struct kvm_io_device *this,
> +				       gpa_t addr, int len, void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_v3r_propbase(struct kvm_vcpu *vcpu,
> +				        struct kvm_io_device *this,
> +				        gpa_t addr, int len, const void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_read_v3r_pendbase(struct kvm_vcpu *vcpu,
> +				       struct kvm_io_device *this,
> +				       gpa_t addr, int len, void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +
> +static int vgic_mmio_write_v3r_pendbase(struct kvm_vcpu *vcpu,
> +				        struct kvm_io_device *this,
> +				        gpa_t addr, int len, const void *val)
> +{
> +	/* TODO: implement */
> +	return 0;
> +}
> +#endif
> +
> +/*
> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
> + * redistributors, while SPIs are covered by registers in the distributor
> + * block. Trying to set private IRQs in this block gets ignored.
> + * We take some special care here to fix the calculation of the register
> + * offset.
> + */
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(name, read_ops, write_ops, bpi) \
> +	{.reg_offset = name, .bits_per_irq = 0, \
> +	 .len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
> +	 .ops.read = vgic_mmio_read_raz, .ops.write = vgic_mmio_write_wi, }, \
> +	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
> +	 .ops.read = read_ops, .ops.write = write_ops, }

why do we have two regions with the same offset and why does the one
that actually implements a handler have length 0 ?

> +
>  struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -626,6 +727,73 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>  		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>  };
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +struct vgic_register_region vgic_v3_dist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> +		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +};
> +
> +struct vgic_register_region vgic_v3_redist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
> +		vgic_mmio_read_v3r_misc, vgic_mmio_write_v3r_misc, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
> +		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
> +		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
> +		vgic_mmio_read_v3r_propbase, vgic_mmio_write_v3r_propbase, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
> +		vgic_mmio_read_v3r_pendbase, vgic_mmio_write_v3r_pendbase, 8),
> +};
> +
> +struct vgic_register_region vgic_v3_private_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +};
> +#endif
> +
>  /*
>   * Using kvm_io_bus_* to access GIC registers directly from userspace does
>   * not work, since we would need the absolute IPA address of the register
> @@ -671,6 +839,24 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>  				is_write, offset, len, val);
>  }
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			int offset, int len, void *val)
> +{
> +	return vgic_mmio_access(vcpu, vgic_v3_dist_registers,
> +				ARRAY_SIZE(vgic_v3_dist_registers),
> +				is_write, offset, len, val);
> +}
> +
> +int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
> +			  int offset, int len, void *val)
> +{
> +	return vgic_mmio_access(vcpu, vgic_v3_redist_registers,
> +				ARRAY_SIZE(vgic_v3_redist_registers),
> +				is_write, offset, len, val);
> +}
> +#endif
> +
>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  				  struct vgic_register_region *reg_desc,
>  				  struct vgic_io_device *region,
> @@ -717,6 +903,12 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>  		reg_desc = vgic_v2_dist_registers;
>  		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>  		break;
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +	case VGIC_V3:
> +		reg_desc = vgic_v3_dist_registers;
> +		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
> +		break;
> +#endif
>  	default:
>  		BUG_ON(1);
>  	}
> @@ -750,3 +942,57 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>  
>  	return ret;
>  }
> +
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
> +{
> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
> +	int nr_regions = ARRAY_SIZE(vgic_v3_redist_registers) +
> +			 ARRAY_SIZE(vgic_v3_private_registers);
> +	struct kvm_vcpu *vcpu;
> +	struct vgic_io_device *regions, *region;
> +	int c, i, ret = 0;
> +
> +	regions = kmalloc(sizeof(struct vgic_io_device) * nr_regions * nr_vcpus,
> +			  GFP_KERNEL);
> +	if (!regions)
> +		return -ENOMEM;
> +
> +	kvm_for_each_vcpu(c, vcpu, kvm) {
> +		region = &regions[c * nr_regions];
> +		for (i = 0; i < ARRAY_SIZE(vgic_v3_redist_registers); i++) {
> +			region->base_addr = redist_base_address;
> +			region->base_addr += c * 2 * SZ_64K;
> +
> +			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
> +						vgic_v3_redist_registers + i,
> +						region, VGIC_NR_PRIVATE_IRQS,
> +						false);
> +			if (ret)
> +				break;
> +			region++;
> +		}
> +		if (ret)
> +			break;
> +
> +		for (i = 0; i < ARRAY_SIZE(vgic_v3_private_registers); i++) {
> +			region->base_addr = redist_base_address;
> +			region->base_addr += c * 2 * SZ_64K + SZ_64K;
> +			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
> +						vgic_v3_private_registers + i,
> +						region, VGIC_NR_PRIVATE_IRQS,
> +						false);
> +			if (ret)
> +				break;
> +			region++;
> +		}
> +		if (ret)
> +			break;
> +	}
> +
> +	if (!ret)
> +		kvm->arch.vgic.redist_iodevs = regions;
> +
> +	return ret;

I'm not going to review all this in detail until we've figured out the
general approach to the IO bus stuff.

> +}
> +#endif
> -- 
> 2.7.3
> 
> --
> 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] 276+ messages in thread

* Re: [RFC PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31 11:53     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 11:53 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:47AM +0000, Andre Przywara wrote:
> As in the GICv2 emulation we handle those three registers in one
> function.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.h      |  2 ++
>  virt/kvm/arm/vgic/vgic_mmio.c | 38 ++++++++++++++++++++++++++++++++++++--
>  2 files changed, 38 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 4b8952a..0db1abe 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -19,6 +19,8 @@
>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>  #define IMPLEMENTER_ARM		0x43b
>  
> +#define INTERRUPT_ID_BITS_SPIS	10
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 2d10c06..13e101f 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -606,7 +606,29 @@ static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
>  				  struct kvm_io_device *this,
>  				  gpa_t addr, int len, void *val)
>  {
> -	/* TODO: implement */
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 value = 0;
> +
> +	switch ((addr - iodev->base_addr) & ~3) {
> +	case GICD_CTLR:
> +		if (vcpu->kvm->arch.vgic.enabled)
> +		       value |=	GICD_CTLR_ENABLE_SS_G1;
> +		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
> +		break;
> +	case GICD_TYPER:
> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +		value = (value >> 5) - 1;
> +		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
> +		break;
> +	case GICD_IIDR:
> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
>  	return 0;
>  }
>  
> @@ -614,7 +636,19 @@ static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
>  				   struct kvm_io_device *this,
>  				   gpa_t addr, int len, const void *val)
>  {
> -	/* TODO: implement */
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	bool enabled;
> +
> +	/* These are not the bits you are looking for ... */

haha, nice.  But I don't understand what this case is?

> +	if (addr - iodev->base_addr > 0)
> +		return 0;
> +
> +	/* We only care about the enable bit, all other bits are WI. */
> +	enabled = *(u8*)val & GICD_CTLR_ENABLE_SS_G1;
> +
> +	vcpu->kvm->arch.vgic.enabled = enabled;

I think some of the comments from the v2 side apply here as well.

> +
>  	return 0;
>  }
>  
> -- 
> 2.7.3
> 

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

* [RFC PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
@ 2016-03-31 11:53     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 11:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:47AM +0000, Andre Przywara wrote:
> As in the GICv2 emulation we handle those three registers in one
> function.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.h      |  2 ++
>  virt/kvm/arm/vgic/vgic_mmio.c | 38 ++++++++++++++++++++++++++++++++++++--
>  2 files changed, 38 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 4b8952a..0db1abe 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -19,6 +19,8 @@
>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>  #define IMPLEMENTER_ARM		0x43b
>  
> +#define INTERRUPT_ID_BITS_SPIS	10
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 2d10c06..13e101f 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -606,7 +606,29 @@ static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
>  				  struct kvm_io_device *this,
>  				  gpa_t addr, int len, void *val)
>  {
> -	/* TODO: implement */
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	u32 value = 0;
> +
> +	switch ((addr - iodev->base_addr) & ~3) {
> +	case GICD_CTLR:
> +		if (vcpu->kvm->arch.vgic.enabled)
> +		       value |=	GICD_CTLR_ENABLE_SS_G1;
> +		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
> +		break;
> +	case GICD_TYPER:
> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +		value = (value >> 5) - 1;
> +		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
> +		break;
> +	case GICD_IIDR:
> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	write_mask32(value, addr & 3, len, val);
>  	return 0;
>  }
>  
> @@ -614,7 +636,19 @@ static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
>  				   struct kvm_io_device *this,
>  				   gpa_t addr, int len, const void *val)
>  {
> -	/* TODO: implement */
> +	struct vgic_io_device *iodev = container_of(this,
> +						    struct vgic_io_device, dev);
> +	bool enabled;
> +
> +	/* These are not the bits you are looking for ... */

haha, nice.  But I don't understand what this case is?

> +	if (addr - iodev->base_addr > 0)
> +		return 0;
> +
> +	/* We only care about the enable bit, all other bits are WI. */
> +	enabled = *(u8*)val & GICD_CTLR_ENABLE_SS_G1;
> +
> +	vcpu->kvm->arch.vgic.enabled = enabled;

I think some of the comments from the v2 side apply here as well.

> +
>  	return 0;
>  }
>  
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
  2016-03-25  2:04   ` Andre Przywara
@ 2016-03-31 12:07     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 12:07 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:51AM +0000, Andre Przywara wrote:
> In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
> by a MMIO write, but with a system register write. KVM knows about
> that register already, we just need to implement the handler and wire
> it up to the core KVM/ARM code.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h       |   8 ++++
>  virt/kvm/arm/vgic/vgic_mmio.c | 101 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 109 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index a8262c7..ab5fcc7 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -202,6 +202,14 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>  void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>  void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
> +#else
> +static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
> +{
> +}
> +#endif
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 44fdba5..7eb6b93 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -1139,4 +1139,105 @@ int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
>  
>  	return ret;
>  }
> +
> +/*
> + * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
> + * generation register ICC_SGI1R_EL1) with a given VCPU.
> + * If the VCPU's MPIDR matches, return the level0 affinity, otherwise
> + * return -1.
> + */
> +static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct kvm_vcpu *vcpu)
> +{
> +	unsigned long affinity;
> +	int level0;
> +
> +	/*
> +	 * Split the current VCPU's MPIDR into affinity level 0 and the
> +	 * rest as this is what we have to compare against.
> +	 */
> +	affinity = kvm_vcpu_get_mpidr_aff(vcpu);
> +	level0 = MPIDR_AFFINITY_LEVEL(affinity, 0);
> +	affinity &= ~MPIDR_LEVEL_MASK;
> +
> +	/* bail out if the upper three levels don't match */
> +	if (sgi_aff != affinity)
> +		return -1;
> +
> +	/* Is this VCPU's bit set in the mask ? */
> +	if (!(sgi_cpu_mask & BIT(level0)))
> +		return -1;
> +
> +	return level0;
> +}
> +
> +#define SGI_AFFINITY_LEVEL(reg, level) \
> +	((((reg) & ICC_SGI1R_AFFINITY_## level ##_MASK) \
> +	>> ICC_SGI1R_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))

wholy crap?  What is this?  Yikes, this is already in the kernel.  Oh
well, I'm not going to try to understand it again then.

> +
> +/**
> + * vgic_v3_dispatch_sgi - handle SGI requests from VCPUs
> + * @vcpu: The VCPU requesting a SGI
> + * @reg: The value written into the ICC_SGI1R_EL1 register by that VCPU
> + *
> + * With GICv3 (and ARE=1) CPUs trigger SGIs by writing to a system register.
> + * This will trap in sys_regs.c and call this function.
> + * This ICC_SGI1R_EL1 register contains the upper three affinity levels of the
> + * target processors as well as a bitmask of 16 Aff0 CPUs.
> + * If the interrupt routing mode bit is not set, we iterate over all VCPUs to
> + * check for matching ones. If this bit is set, we signal all, but not the
> + * calling VCPU.
> + */
> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
> +{
> +	struct kvm *kvm = vcpu->kvm;
> +	struct kvm_vcpu *c_vcpu;
> +	u16 target_cpus;
> +	u64 mpidr;
> +	int sgi, c;
> +	int vcpu_id = vcpu->vcpu_id;
> +	bool broadcast;
> +
> +	sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
> +	broadcast = reg & BIT(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
> +	target_cpus = (reg & ICC_SGI1R_TARGET_LIST_MASK) >> ICC_SGI1R_TARGET_LIST_SHIFT;
> +	mpidr = SGI_AFFINITY_LEVEL(reg, 3);
> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 2);
> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 1);
> +
> +	/*
> +	 * We iterate over all VCPUs to find the MPIDRs matching the request.
> +	 * If we have handled one CPU, we clear it's bit to detect early

s/it's/its/

> +	 * if we are already finished. This avoids iterating through all
> +	 * VCPUs when most of the times we just signal a single VCPU.
> +	 */
> +	kvm_for_each_vcpu(c, c_vcpu, kvm) {
> +		struct vgic_irq *irq;
> +
> +		/* Exit early if we have dealt with all requested CPUs */
> +		if (!broadcast && target_cpus == 0)
> +			break;
> +
> +		/* Don't signal the calling VCPU */
> +		if (broadcast && c == vcpu_id)
> +			continue;
> +
> +		if (!broadcast) {
> +			int level0;
> +
> +			level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
> +			if (level0 == -1)
> +				continue;
> +
> +			/* remove this matching VCPU from the mask */
> +			target_cpus &= ~BIT(level0);
> +		}
> +
> +		irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +
> +		vgic_queue_irq(vcpu->kvm, irq);
> +	}

eventually I suspect we should implement a linear time 'give me a vcpu
based on this mpidr' lookup function, but this should be fine for now.

> +}
>  #endif
> -- 
> 2.7.3
> 
> --
> 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] 276+ messages in thread

* [RFC PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
@ 2016-03-31 12:07     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:51AM +0000, Andre Przywara wrote:
> In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
> by a MMIO write, but with a system register write. KVM knows about
> that register already, we just need to implement the handler and wire
> it up to the core KVM/ARM code.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h       |   8 ++++
>  virt/kvm/arm/vgic/vgic_mmio.c | 101 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 109 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index a8262c7..ab5fcc7 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -202,6 +202,14 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>  void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>  void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
> +#else
> +static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
> +{
> +}
> +#endif
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 44fdba5..7eb6b93 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -1139,4 +1139,105 @@ int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
>  
>  	return ret;
>  }
> +
> +/*
> + * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
> + * generation register ICC_SGI1R_EL1) with a given VCPU.
> + * If the VCPU's MPIDR matches, return the level0 affinity, otherwise
> + * return -1.
> + */
> +static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct kvm_vcpu *vcpu)
> +{
> +	unsigned long affinity;
> +	int level0;
> +
> +	/*
> +	 * Split the current VCPU's MPIDR into affinity level 0 and the
> +	 * rest as this is what we have to compare against.
> +	 */
> +	affinity = kvm_vcpu_get_mpidr_aff(vcpu);
> +	level0 = MPIDR_AFFINITY_LEVEL(affinity, 0);
> +	affinity &= ~MPIDR_LEVEL_MASK;
> +
> +	/* bail out if the upper three levels don't match */
> +	if (sgi_aff != affinity)
> +		return -1;
> +
> +	/* Is this VCPU's bit set in the mask ? */
> +	if (!(sgi_cpu_mask & BIT(level0)))
> +		return -1;
> +
> +	return level0;
> +}
> +
> +#define SGI_AFFINITY_LEVEL(reg, level) \
> +	((((reg) & ICC_SGI1R_AFFINITY_## level ##_MASK) \
> +	>> ICC_SGI1R_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))

wholy crap?  What is this?  Yikes, this is already in the kernel.  Oh
well, I'm not going to try to understand it again then.

> +
> +/**
> + * vgic_v3_dispatch_sgi - handle SGI requests from VCPUs
> + * @vcpu: The VCPU requesting a SGI
> + * @reg: The value written into the ICC_SGI1R_EL1 register by that VCPU
> + *
> + * With GICv3 (and ARE=1) CPUs trigger SGIs by writing to a system register.
> + * This will trap in sys_regs.c and call this function.
> + * This ICC_SGI1R_EL1 register contains the upper three affinity levels of the
> + * target processors as well as a bitmask of 16 Aff0 CPUs.
> + * If the interrupt routing mode bit is not set, we iterate over all VCPUs to
> + * check for matching ones. If this bit is set, we signal all, but not the
> + * calling VCPU.
> + */
> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
> +{
> +	struct kvm *kvm = vcpu->kvm;
> +	struct kvm_vcpu *c_vcpu;
> +	u16 target_cpus;
> +	u64 mpidr;
> +	int sgi, c;
> +	int vcpu_id = vcpu->vcpu_id;
> +	bool broadcast;
> +
> +	sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
> +	broadcast = reg & BIT(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
> +	target_cpus = (reg & ICC_SGI1R_TARGET_LIST_MASK) >> ICC_SGI1R_TARGET_LIST_SHIFT;
> +	mpidr = SGI_AFFINITY_LEVEL(reg, 3);
> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 2);
> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 1);
> +
> +	/*
> +	 * We iterate over all VCPUs to find the MPIDRs matching the request.
> +	 * If we have handled one CPU, we clear it's bit to detect early

s/it's/its/

> +	 * if we are already finished. This avoids iterating through all
> +	 * VCPUs when most of the times we just signal a single VCPU.
> +	 */
> +	kvm_for_each_vcpu(c, c_vcpu, kvm) {
> +		struct vgic_irq *irq;
> +
> +		/* Exit early if we have dealt with all requested CPUs */
> +		if (!broadcast && target_cpus == 0)
> +			break;
> +
> +		/* Don't signal the calling VCPU */
> +		if (broadcast && c == vcpu_id)
> +			continue;
> +
> +		if (!broadcast) {
> +			int level0;
> +
> +			level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
> +			if (level0 == -1)
> +				continue;
> +
> +			/* remove this matching VCPU from the mask */
> +			target_cpus &= ~BIT(level0);
> +		}
> +
> +		irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +
> +		vgic_queue_irq(vcpu->kvm, irq);
> +	}

eventually I suspect we should implement a linear time 'give me a vcpu
based on this mpidr' lookup function, but this should be fine for now.

> +}
>  #endif
> -- 
> 2.7.3
> 
> --
> 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] 276+ messages in thread

* Re: [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-03-31  9:09       ` Christoffer Dall
@ 2016-03-31 12:25         ` Paolo Bonzini
  -1 siblings, 0 replies; 276+ messages in thread
From: Paolo Bonzini @ 2016-03-31 12:25 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara
  Cc: Marc Zyngier, Eric Auger, linux-arm-kernel, kvmarm, kvm



On 31/03/2016 11:09, Christoffer Dall wrote:
>> My comments to Vladimir's bug report notwithstanding, there's still a
>> choice here to:
>>
>> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
>>
>> 2) Build a KVM architectureal generic framework on top of the IO bus
>> framework to handle individual register regions.
>>
>> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
>> and handle the individual register region business locally within the
>> arm/vgic code.

I prefer 3, or alternatively just add the framework in virt/kvm/arm so
that it can be migrated to virt/kvm if someone else needs it.

Paolo

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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-03-31 12:25         ` Paolo Bonzini
  0 siblings, 0 replies; 276+ messages in thread
From: Paolo Bonzini @ 2016-03-31 12:25 UTC (permalink / raw)
  To: linux-arm-kernel



On 31/03/2016 11:09, Christoffer Dall wrote:
>> My comments to Vladimir's bug report notwithstanding, there's still a
>> choice here to:
>>
>> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
>>
>> 2) Build a KVM architectureal generic framework on top of the IO bus
>> framework to handle individual register regions.
>>
>> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
>> and handle the individual register region business locally within the
>> arm/vgic code.

I prefer 3, or alternatively just add the framework in virt/kvm/arm so
that it can be migrated to virt/kvm if someone else needs it.

Paolo

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

* Re: [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-03-31 12:25         ` Paolo Bonzini
@ 2016-03-31 14:31           ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 14:31 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Andre Przywara, Marc Zyngier, Eric Auger, linux-arm-kernel, kvmarm, kvm

On Thu, Mar 31, 2016 at 02:25:02PM +0200, Paolo Bonzini wrote:
> 
> 
> On 31/03/2016 11:09, Christoffer Dall wrote:
> >> My comments to Vladimir's bug report notwithstanding, there's still a
> >> choice here to:
> >>
> >> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> >>
> >> 2) Build a KVM architectureal generic framework on top of the IO bus
> >> framework to handle individual register regions.
> >>
> >> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> >> and handle the individual register region business locally within the
> >> arm/vgic code.
> 
> I prefer 3, or alternatively just add the framework in virt/kvm/arm so
> that it can be migrated to virt/kvm if someone else needs it.
> 
Sounds like a plan.  Thanks Paolo.

-Christoffer

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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-03-31 14:31           ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 31, 2016 at 02:25:02PM +0200, Paolo Bonzini wrote:
> 
> 
> On 31/03/2016 11:09, Christoffer Dall wrote:
> >> My comments to Vladimir's bug report notwithstanding, there's still a
> >> choice here to:
> >>
> >> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> >>
> >> 2) Build a KVM architectureal generic framework on top of the IO bus
> >> framework to handle individual register regions.
> >>
> >> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> >> and handle the individual register region business locally within the
> >> arm/vgic code.
> 
> I prefer 3, or alternatively just add the framework in virt/kvm/arm so
> that it can be migrated to virt/kvm if someone else needs it.
> 
Sounds like a plan.  Thanks Paolo.

-Christoffer

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

* Re: [RFC PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
  2016-03-25  2:05   ` Andre Przywara
@ 2016-03-31 17:59     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 17:59 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:05:03AM +0000, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch allocates and initializes the data structures used
> to model the vgic distributor and virtual cpu interfaces. At that
> stage the number of IRQs and number of virtual CPUs is frozen.
> 
> The following realy_init functions are kept since they are called from
> arm.c. However they may disappear in subsequent patches since
> they are void.
> 
> vgic_[v2|v3]_enable still is stubbed at this stage.

early init ?

> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h       |   7 +-
>  virt/kvm/arm/vgic/vgic-v2.c   |   5 +
>  virt/kvm/arm/vgic/vgic-v3.c   |   5 +
>  virt/kvm/arm/vgic/vgic.c      |   5 +
>  virt/kvm/arm/vgic/vgic.h      |   8 ++
>  virt/kvm/arm/vgic/vgic_init.c | 214 ++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 243 insertions(+), 1 deletion(-)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 536582b..4a51582 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -115,6 +115,7 @@ struct vgic_io_device {
>  struct vgic_dist {
>  	bool			in_kernel;
>  	bool			ready;
> +	bool			initialized;
>  
>  	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>  	u32			vgic_model;
> @@ -195,7 +196,11 @@ struct vgic_cpu {
>  };
>  
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
> +void kvm_vgic_early_init(struct kvm *kvm);
>  int kvm_vgic_create(struct kvm *kvm, u32 type);
> +void kvm_vgic_destroy(struct kvm *kvm);
> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
>  int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> @@ -204,7 +209,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> -#define vgic_initialized(k)	(false)
> +#define vgic_initialized(k)	((k)->arch.vgic.initialized)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 0cb5c4f..c48dbd4 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -234,6 +234,11 @@ void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>  	spin_unlock(&irq->irq_lock);
>  }
>  
> +/* not yet implemented */
> +void vgic_v2_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /**
>   * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 1a53141..3155680 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -220,6 +220,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>  }
>  
> +/* not yet implemented */
> +void vgic_v3_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /**
>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 8c19379..4ade7c0 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -268,6 +268,11 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level)
>  {
>  	struct kvm_vcpu *vcpu;
> +	int ret;
> +
> +	ret = vgic_lazy_init(kvm);
> +	if (ret)
> +		return ret;
>  
>  	vcpu = kvm_get_vcpu(kvm, cpuid);
>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 31c9299a..4b2e1b0 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -38,6 +38,7 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v2_enable(struct kvm_vcpu *vcpu);
>  int vgic_v2_probe(struct device_node *vgic_node);
>  
>  #ifdef CONFIG_KVM_ARM_VGIC_V3
> @@ -52,6 +53,7 @@ int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
>  			  int offset, int len, void *val);
>  void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v3_enable(struct kvm_vcpu *vcpu);
>  int vgic_v3_probe(struct device_node *vgic_node);
>  #else
>  static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
> @@ -98,6 +100,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>  {
>  }
>  
> +static inline void vgic_v3_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  static inline int vgic_v3_probe(struct device_node *vgic_node)
>  {
>  	return -ENODEV;
> @@ -107,6 +113,8 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
>  void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  
> +int vgic_lazy_init(struct kvm *kvm);
> +int vgic_init(struct kvm *kvm);
>  void kvm_register_vgic_device(unsigned long type);
>  
>  #endif
> diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
> index 80bf283..f7a6a11 100644
> --- a/virt/kvm/arm/vgic/vgic_init.c
> +++ b/virt/kvm/arm/vgic/vgic_init.c
> @@ -24,6 +24,42 @@
>  #include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
> +/*
> + * Initialization rules: there are multiple stages to the vgic
> + * initialization, both for the distributor and the CPU interfaces.
> + *
> + * Distributor:
> + *
> + * - kvm_vgic_early_init(): initialization of static data that doesn't
> + *   depend on any sizing information or emulation type. No allocation
> + *   is allowed there.
> + *
> + * - vgic_init(): allocation and initialization of the generic data
> + *   structures that depend on sizing information (number of CPUs,
> + *   number of interrupts). Also initializes the vcpu specific data
> + *   structures. Can be executed lazily for GICv2.
> + *
> + * CPU Interface:
> + *
> + * - kvm_vgic_cpu_early_init(): initialization of static data that
> + *   doesn't depend on any sizing information or emulation type. No
> + *   allocation is allowed there.
> + */
> +
> +/* EARLY INIT */
> +
> +/*
> + * Those 2 functions should not be needed anymore but they
> + * still are called from arm.c
> + */
> +void kvm_vgic_early_init(struct kvm *kvm)
> +{
> +}
> +
> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /* CREATION */
>  
>  /**
> @@ -108,6 +144,184 @@ out:
>  	return ret;
>  }
>  
> +/* INIT/DESTROY */
> +
> +/**
> + * kvm_vgic_dist_init: initialize the dist data structures
> + * @kvm: kvm struct pointer
> + * @nr_spis: number of spis, frozen by caller
> + */
> +int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	int i;
> +
> +	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
> +	if (!dist->spis)
> +		return  -ENOMEM;
> +
> +	/*
> +	 * In following code we do not take the irq struct lock since
> +	 * no other action on irq structs can happen while the VGIC is
> +	 * not initialized yet:
> +	 * injection requires (VGICV3) or does (VGIC2) initialization.
> +	 * MMIO access triggers init.
> +	 */
> +	for (i = 0; i < nr_spis; i++) {
> +		struct vgic_irq *irq = &dist->spis[i];
> +
> +		irq->intid = i + VGIC_NR_PRIVATE_IRQS;
> +		INIT_LIST_HEAD(&irq->ap_list);
> +		spin_lock_init(&irq->irq_lock);
> +		irq->vcpu = NULL;
> +		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
> +			vgic_v2_irq_change_affinity(kvm, irq->intid, 0);
> +		else
> +			vgic_v3_irq_change_affinity(kvm, irq->intid, 0);
> +	}
> +	return 0;
> +}
> +
> +/**
> + * kvm_vgic_vcpu_init: initialize the vcpu data structures and
> + * enable the VCPU interface
> + * @kvm: kvm struct pointer
> + */
> +void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	int i;
> +
> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> +	spin_lock_init(&vgic_cpu->ap_list_lock);
> +	vgic_cpu->nr_lr = kvm_vgic_global_state.nr_lr;
> +
> +	/*
> +	 * Enable and configure all SGIs to be edge-triggered and
> +	 * configure all PPIs as level-triggered.
> +	 */
> +	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
> +		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
> +
> +		INIT_LIST_HEAD(&irq->ap_list);

I don't think this is strictly required, but ok.

> +		spin_lock_init(&irq->irq_lock);
> +		irq->intid = i;
> +		irq->vcpu = NULL;
> +		irq->target_vcpu = vcpu;
> +		irq->targets = 1U << vcpu->vcpu_id;
> +		if (i < VGIC_NR_SGIS) {
> +			/* SGIs */
> +			irq->enabled = 1;
> +			irq->config = VGIC_CONFIG_EDGE;
> +		} else {
> +			/* PPIs */
> +			irq->config = VGIC_CONFIG_LEVEL;
> +		}
> +	}
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_enable(vcpu);
> +	else
> +		vgic_v3_enable(vcpu);
> +}
> +
> +/*
> + * vgic_init: allocates and initializes dist and vcpu data structures
> + * depending on two dimensioning parameters:
> + * - the number of spis
> + * - the number of vcpus
> + * The function is generally called when nr_spis has been explicitly set
> + * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
> + * Completion can be tested by vgic_initialized
> + * Must be called with kvm->lock held!
> + */
> +int vgic_init(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct kvm_vcpu *vcpu;
> +	int ret = 0, i;
> +
> +	if (vgic_initialized(kvm))
> +		return 0;
> +
> +	/* freeze the number of spis */
> +	if (!dist->nr_spis)
> +		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
> +
> +	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
> +	if (ret)
> +		goto out;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm)
> +		kvm_vgic_vcpu_init(vcpu);
> +
> +	dist->initialized = true;
> +out:
> +	return ret;
> +}
> +
> +static void kvm_vgic_dist_destroy(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +
> +	mutex_lock(&kvm->lock);
> +
> +	dist->ready = false;
> +	dist->initialized = false;
> +
> +	kfree(dist->spis);
> +	kfree(dist->dist_iodevs);
> +	kfree(dist->redist_iodevs);
> +	dist->nr_spis = 0;
> +
> +	mutex_unlock(&kvm->lock);
> +}
> +
> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +
> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> +	vgic_cpu->nr_lr = 0;
> +}
> +
> +void kvm_vgic_destroy(struct kvm *kvm)
> +{
> +	struct kvm_vcpu *vcpu;
> +	int i;
> +
> +	kvm_vgic_dist_destroy(kvm);
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm)
> +		kvm_vgic_vcpu_destroy(vcpu);
> +}
> +
> +/**
> + * Lazy init only is allowed if the GIC exposed to the guest is a GICV2.
> + * GICV3 must be explicitly initialized by the guest using the
> + * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group
> + */
> +int vgic_lazy_init(struct kvm *kvm)
> +{
> +	int ret = 0;
> +
> +	if (unlikely(!vgic_initialized(kvm))) {
> +		/*
> +		 * We only provide the automatic initialization of the VGIC
> +		 * for the legacy case of a GICv2. Any other type must
> +		 * be explicitly initialized once setup with the respective
> +		 * KVM device call.
> +		 */
> +		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
> +			return -EBUSY;
> +
> +		mutex_lock(&kvm->lock);
> +		ret = vgic_init(kvm);
> +		mutex_unlock(&kvm->lock);
> +	}
> +
> +	return ret;
> +}
> +
>  /* GENERIC PROBE */
>  
>  static void vgic_init_maintenance_interrupt(void *info)
> -- 
> 2.7.3
> 

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

* [RFC PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
@ 2016-03-31 17:59     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 17:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:05:03AM +0000, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch allocates and initializes the data structures used
> to model the vgic distributor and virtual cpu interfaces. At that
> stage the number of IRQs and number of virtual CPUs is frozen.
> 
> The following realy_init functions are kept since they are called from
> arm.c. However they may disappear in subsequent patches since
> they are void.
> 
> vgic_[v2|v3]_enable still is stubbed at this stage.

early init ?

> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h       |   7 +-
>  virt/kvm/arm/vgic/vgic-v2.c   |   5 +
>  virt/kvm/arm/vgic/vgic-v3.c   |   5 +
>  virt/kvm/arm/vgic/vgic.c      |   5 +
>  virt/kvm/arm/vgic/vgic.h      |   8 ++
>  virt/kvm/arm/vgic/vgic_init.c | 214 ++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 243 insertions(+), 1 deletion(-)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 536582b..4a51582 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -115,6 +115,7 @@ struct vgic_io_device {
>  struct vgic_dist {
>  	bool			in_kernel;
>  	bool			ready;
> +	bool			initialized;
>  
>  	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>  	u32			vgic_model;
> @@ -195,7 +196,11 @@ struct vgic_cpu {
>  };
>  
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
> +void kvm_vgic_early_init(struct kvm *kvm);
>  int kvm_vgic_create(struct kvm *kvm, u32 type);
> +void kvm_vgic_destroy(struct kvm *kvm);
> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
>  int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> @@ -204,7 +209,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> -#define vgic_initialized(k)	(false)
> +#define vgic_initialized(k)	((k)->arch.vgic.initialized)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 0cb5c4f..c48dbd4 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -234,6 +234,11 @@ void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>  	spin_unlock(&irq->irq_lock);
>  }
>  
> +/* not yet implemented */
> +void vgic_v2_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /**
>   * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 1a53141..3155680 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -220,6 +220,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>  }
>  
> +/* not yet implemented */
> +void vgic_v3_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /**
>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 8c19379..4ade7c0 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -268,6 +268,11 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level)
>  {
>  	struct kvm_vcpu *vcpu;
> +	int ret;
> +
> +	ret = vgic_lazy_init(kvm);
> +	if (ret)
> +		return ret;
>  
>  	vcpu = kvm_get_vcpu(kvm, cpuid);
>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 31c9299a..4b2e1b0 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -38,6 +38,7 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v2_enable(struct kvm_vcpu *vcpu);
>  int vgic_v2_probe(struct device_node *vgic_node);
>  
>  #ifdef CONFIG_KVM_ARM_VGIC_V3
> @@ -52,6 +53,7 @@ int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
>  			  int offset, int len, void *val);
>  void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v3_enable(struct kvm_vcpu *vcpu);
>  int vgic_v3_probe(struct device_node *vgic_node);
>  #else
>  static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
> @@ -98,6 +100,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>  {
>  }
>  
> +static inline void vgic_v3_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  static inline int vgic_v3_probe(struct device_node *vgic_node)
>  {
>  	return -ENODEV;
> @@ -107,6 +113,8 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
>  void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  
> +int vgic_lazy_init(struct kvm *kvm);
> +int vgic_init(struct kvm *kvm);
>  void kvm_register_vgic_device(unsigned long type);
>  
>  #endif
> diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
> index 80bf283..f7a6a11 100644
> --- a/virt/kvm/arm/vgic/vgic_init.c
> +++ b/virt/kvm/arm/vgic/vgic_init.c
> @@ -24,6 +24,42 @@
>  #include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
> +/*
> + * Initialization rules: there are multiple stages to the vgic
> + * initialization, both for the distributor and the CPU interfaces.
> + *
> + * Distributor:
> + *
> + * - kvm_vgic_early_init(): initialization of static data that doesn't
> + *   depend on any sizing information or emulation type. No allocation
> + *   is allowed there.
> + *
> + * - vgic_init(): allocation and initialization of the generic data
> + *   structures that depend on sizing information (number of CPUs,
> + *   number of interrupts). Also initializes the vcpu specific data
> + *   structures. Can be executed lazily for GICv2.
> + *
> + * CPU Interface:
> + *
> + * - kvm_vgic_cpu_early_init(): initialization of static data that
> + *   doesn't depend on any sizing information or emulation type. No
> + *   allocation is allowed there.
> + */
> +
> +/* EARLY INIT */
> +
> +/*
> + * Those 2 functions should not be needed anymore but they
> + * still are called from arm.c
> + */
> +void kvm_vgic_early_init(struct kvm *kvm)
> +{
> +}
> +
> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /* CREATION */
>  
>  /**
> @@ -108,6 +144,184 @@ out:
>  	return ret;
>  }
>  
> +/* INIT/DESTROY */
> +
> +/**
> + * kvm_vgic_dist_init: initialize the dist data structures
> + * @kvm: kvm struct pointer
> + * @nr_spis: number of spis, frozen by caller
> + */
> +int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	int i;
> +
> +	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
> +	if (!dist->spis)
> +		return  -ENOMEM;
> +
> +	/*
> +	 * In following code we do not take the irq struct lock since
> +	 * no other action on irq structs can happen while the VGIC is
> +	 * not initialized yet:
> +	 * injection requires (VGICV3) or does (VGIC2) initialization.
> +	 * MMIO access triggers init.
> +	 */
> +	for (i = 0; i < nr_spis; i++) {
> +		struct vgic_irq *irq = &dist->spis[i];
> +
> +		irq->intid = i + VGIC_NR_PRIVATE_IRQS;
> +		INIT_LIST_HEAD(&irq->ap_list);
> +		spin_lock_init(&irq->irq_lock);
> +		irq->vcpu = NULL;
> +		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
> +			vgic_v2_irq_change_affinity(kvm, irq->intid, 0);
> +		else
> +			vgic_v3_irq_change_affinity(kvm, irq->intid, 0);
> +	}
> +	return 0;
> +}
> +
> +/**
> + * kvm_vgic_vcpu_init: initialize the vcpu data structures and
> + * enable the VCPU interface
> + * @kvm: kvm struct pointer
> + */
> +void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	int i;
> +
> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> +	spin_lock_init(&vgic_cpu->ap_list_lock);
> +	vgic_cpu->nr_lr = kvm_vgic_global_state.nr_lr;
> +
> +	/*
> +	 * Enable and configure all SGIs to be edge-triggered and
> +	 * configure all PPIs as level-triggered.
> +	 */
> +	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
> +		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
> +
> +		INIT_LIST_HEAD(&irq->ap_list);

I don't think this is strictly required, but ok.

> +		spin_lock_init(&irq->irq_lock);
> +		irq->intid = i;
> +		irq->vcpu = NULL;
> +		irq->target_vcpu = vcpu;
> +		irq->targets = 1U << vcpu->vcpu_id;
> +		if (i < VGIC_NR_SGIS) {
> +			/* SGIs */
> +			irq->enabled = 1;
> +			irq->config = VGIC_CONFIG_EDGE;
> +		} else {
> +			/* PPIs */
> +			irq->config = VGIC_CONFIG_LEVEL;
> +		}
> +	}
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_enable(vcpu);
> +	else
> +		vgic_v3_enable(vcpu);
> +}
> +
> +/*
> + * vgic_init: allocates and initializes dist and vcpu data structures
> + * depending on two dimensioning parameters:
> + * - the number of spis
> + * - the number of vcpus
> + * The function is generally called when nr_spis has been explicitly set
> + * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
> + * Completion can be tested by vgic_initialized
> + * Must be called with kvm->lock held!
> + */
> +int vgic_init(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct kvm_vcpu *vcpu;
> +	int ret = 0, i;
> +
> +	if (vgic_initialized(kvm))
> +		return 0;
> +
> +	/* freeze the number of spis */
> +	if (!dist->nr_spis)
> +		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
> +
> +	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
> +	if (ret)
> +		goto out;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm)
> +		kvm_vgic_vcpu_init(vcpu);
> +
> +	dist->initialized = true;
> +out:
> +	return ret;
> +}
> +
> +static void kvm_vgic_dist_destroy(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +
> +	mutex_lock(&kvm->lock);
> +
> +	dist->ready = false;
> +	dist->initialized = false;
> +
> +	kfree(dist->spis);
> +	kfree(dist->dist_iodevs);
> +	kfree(dist->redist_iodevs);
> +	dist->nr_spis = 0;
> +
> +	mutex_unlock(&kvm->lock);
> +}
> +
> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +
> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> +	vgic_cpu->nr_lr = 0;
> +}
> +
> +void kvm_vgic_destroy(struct kvm *kvm)
> +{
> +	struct kvm_vcpu *vcpu;
> +	int i;
> +
> +	kvm_vgic_dist_destroy(kvm);
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm)
> +		kvm_vgic_vcpu_destroy(vcpu);
> +}
> +
> +/**
> + * Lazy init only is allowed if the GIC exposed to the guest is a GICV2.
> + * GICV3 must be explicitly initialized by the guest using the
> + * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group
> + */
> +int vgic_lazy_init(struct kvm *kvm)
> +{
> +	int ret = 0;
> +
> +	if (unlikely(!vgic_initialized(kvm))) {
> +		/*
> +		 * We only provide the automatic initialization of the VGIC
> +		 * for the legacy case of a GICv2. Any other type must
> +		 * be explicitly initialized once setup with the respective
> +		 * KVM device call.
> +		 */
> +		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
> +			return -EBUSY;
> +
> +		mutex_lock(&kvm->lock);
> +		ret = vgic_init(kvm);
> +		mutex_unlock(&kvm->lock);
> +	}
> +
> +	return ret;
> +}
> +
>  /* GENERIC PROBE */
>  
>  static void vgic_init_maintenance_interrupt(void *info)
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 43/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
  2016-03-25  2:05   ` Andre Przywara
@ 2016-03-31 18:15     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 18:15 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:05:06AM +0000, Andre Przywara wrote:
> We now store the mapped hardware IRQ number in our struct, so we
> don't need the irq_phys_map any longer for the new VGIC.
> Implement the hardware IRQ mapping on top of the reworked arch
> timer interface.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h  | 15 ++++++++
>  virt/kvm/arm/vgic/vgic.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 107 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index e418de9..7c1d145 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -206,6 +206,21 @@ int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level);
> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			       bool level);
> +
> +/*
> + * This is not really needed, but we need this type to keep the arch
> + * timer compatible with the old VGIC implementation.
> + * This should be removed upon retiring the old VGIC.
> + */
> +struct irq_phys_map {};
> +
> +struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
> +					   u32 virt_irq, u32 irq);
> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
> +			    u32 intid);
> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid);
>  
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 4ade7c0..65395af 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -17,6 +17,9 @@
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
>  #include <linux/list_sort.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/irqdesc.h>
>  
>  #include "vgic.h"
>  
> @@ -276,6 +279,83 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  
>  	vcpu = kvm_get_vcpu(kvm, cpuid);
>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
> +
> +	return 0;
> +}
> +
> +/**
> + * kvm_vgic_inject_mapped_irq - Inject a hardware mapped IRQ to the vgic
> + * @kvm:     The VM structure pointer
> + * @cpuid:   The CPU for PPIs
> + * @irq_num: The INTID to inject a new state to.
> + * @level:   Edge-triggered:  true:  to trigger the interrupt
> + *			      false: to ignore the call
> + *	     Level-sensitive  true:  raise the input signal
> + *			      false: lower the input signal
> + *
> + * The GIC is not concerned with devices being active-LOW or active-HIGH for
> + * level-sensitive interrupts.  You can think of the level parameter as 1
> + * being HIGH and 0 being LOW and all devices being active-HIGH.
> + */
> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			       bool level)
> +{
> +	struct kvm_vcpu *vcpu;
> +	int ret;
> +
> +	ret = vgic_lazy_init(kvm);
> +	if (ret)
> +		return ret;
> +
> +	vcpu = kvm_get_vcpu(kvm, cpuid);
> +	vgic_update_irq_pending(kvm, vcpu, intid, level);
> +
> +	return 0;
> +}
> +
> +struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
> +					   u32 virt_irq, u32 intid)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
> +	struct irq_desc *desc;
> +	struct irq_data *data;
> +
> +	BUG_ON(!irq);
> +
> +	desc = irq_to_desc(intid);

eh, but that's not an INTID, that's a linux IRQ number then right?

> +	if (!desc) {
> +		kvm_err("%s: no interrupt descriptor\n", __func__);
> +		return NULL;
> +	}
> +
> +	data = irq_desc_get_irq_data(desc);
> +	while (data->parent_data)
> +		data = data->parent_data;
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	irq->hw = true;
> +	irq->hwintid = data->hwirq;
> +
> +	spin_unlock(&irq->irq_lock);
> +
> +	return NULL;
> +}
> +
> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
> +			    u32 intid)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +	BUG_ON(!irq);
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	irq->hw = false;
> +	irq->hwintid = 0;
> +
> +	spin_unlock(&irq->irq_lock);
> +
>  	return 0;
>  }
>  
> @@ -520,3 +600,15 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
>  
>  	return pending;
>  }
> +
> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +	bool map_is_active;
> +
> +	spin_lock(&irq->irq_lock);
> +	map_is_active = irq->hw && irq->active;
> +	spin_unlock(&irq->irq_lock);
> +
> +	return map_is_active;
> +}
> -- 
> 2.7.3
> 
> --
> 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] 276+ messages in thread

* [RFC PATCH 43/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
@ 2016-03-31 18:15     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 18:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:05:06AM +0000, Andre Przywara wrote:
> We now store the mapped hardware IRQ number in our struct, so we
> don't need the irq_phys_map any longer for the new VGIC.
> Implement the hardware IRQ mapping on top of the reworked arch
> timer interface.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h  | 15 ++++++++
>  virt/kvm/arm/vgic/vgic.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 107 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index e418de9..7c1d145 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -206,6 +206,21 @@ int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level);
> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			       bool level);
> +
> +/*
> + * This is not really needed, but we need this type to keep the arch
> + * timer compatible with the old VGIC implementation.
> + * This should be removed upon retiring the old VGIC.
> + */
> +struct irq_phys_map {};
> +
> +struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
> +					   u32 virt_irq, u32 irq);
> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
> +			    u32 intid);
> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid);
>  
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 4ade7c0..65395af 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -17,6 +17,9 @@
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
>  #include <linux/list_sort.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/irqdesc.h>
>  
>  #include "vgic.h"
>  
> @@ -276,6 +279,83 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  
>  	vcpu = kvm_get_vcpu(kvm, cpuid);
>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
> +
> +	return 0;
> +}
> +
> +/**
> + * kvm_vgic_inject_mapped_irq - Inject a hardware mapped IRQ to the vgic
> + * @kvm:     The VM structure pointer
> + * @cpuid:   The CPU for PPIs
> + * @irq_num: The INTID to inject a new state to.
> + * @level:   Edge-triggered:  true:  to trigger the interrupt
> + *			      false: to ignore the call
> + *	     Level-sensitive  true:  raise the input signal
> + *			      false: lower the input signal
> + *
> + * The GIC is not concerned with devices being active-LOW or active-HIGH for
> + * level-sensitive interrupts.  You can think of the level parameter as 1
> + * being HIGH and 0 being LOW and all devices being active-HIGH.
> + */
> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			       bool level)
> +{
> +	struct kvm_vcpu *vcpu;
> +	int ret;
> +
> +	ret = vgic_lazy_init(kvm);
> +	if (ret)
> +		return ret;
> +
> +	vcpu = kvm_get_vcpu(kvm, cpuid);
> +	vgic_update_irq_pending(kvm, vcpu, intid, level);
> +
> +	return 0;
> +}
> +
> +struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
> +					   u32 virt_irq, u32 intid)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
> +	struct irq_desc *desc;
> +	struct irq_data *data;
> +
> +	BUG_ON(!irq);
> +
> +	desc = irq_to_desc(intid);

eh, but that's not an INTID, that's a linux IRQ number then right?

> +	if (!desc) {
> +		kvm_err("%s: no interrupt descriptor\n", __func__);
> +		return NULL;
> +	}
> +
> +	data = irq_desc_get_irq_data(desc);
> +	while (data->parent_data)
> +		data = data->parent_data;
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	irq->hw = true;
> +	irq->hwintid = data->hwirq;
> +
> +	spin_unlock(&irq->irq_lock);
> +
> +	return NULL;
> +}
> +
> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
> +			    u32 intid)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +	BUG_ON(!irq);
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	irq->hw = false;
> +	irq->hwintid = 0;
> +
> +	spin_unlock(&irq->irq_lock);
> +
>  	return 0;
>  }
>  
> @@ -520,3 +600,15 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
>  
>  	return pending;
>  }
> +
> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +	bool map_is_active;
> +
> +	spin_lock(&irq->irq_lock);
> +	map_is_active = irq->hw && irq->active;
> +	spin_unlock(&irq->irq_lock);
> +
> +	return map_is_active;
> +}
> -- 
> 2.7.3
> 
> --
> 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] 276+ messages in thread

* Re: [RFC PATCH 44/45] KVM: arm/arm64: vgic-new: Add dummy MSI implementation
  2016-03-25  2:05   ` Andre Przywara
@ 2016-03-31 18:16     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 18:16 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:05:07AM +0000, Andre Przywara wrote:
> Although we don't provide any virtual MSI functionality yet, we
> need to implement the functions required by the KVM interface.

I don't feel like this commit text accurately describes what's happening
in the code?

This seems to be about irqfds which work just fine on a GICv2m guest?

Thanks,
-Christoffer

> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_irqfd.c | 51 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 51 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic_irqfd.c b/virt/kvm/arm/vgic/vgic_irqfd.c
> new file mode 100644
> index 0000000..3eee1bd
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic_irqfd.c
> @@ -0,0 +1,51 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * 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/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <trace/events/kvm.h>
> +
> +int kvm_irq_map_gsi(struct kvm *kvm,
> +		    struct kvm_kernel_irq_routing_entry *entries,
> +		    int gsi)
> +{
> +	return 0;
> +}
> +
> +int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
> +{
> +	return pin;
> +}
> +
> +int kvm_set_irq(struct kvm *kvm, int irq_source_id,
> +		u32 irq, int level, bool line_status)
> +{
> +	unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
> +
> +	trace_kvm_set_irq(irq, level, irq_source_id);
> +
> +	BUG_ON(!vgic_initialized(kvm));
> +
> +	return kvm_vgic_inject_irq(kvm, 0, spi, level);
> +}
> +
> +/* MSI not implemented yet */
> +int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
> +		struct kvm *kvm, int irq_source_id,
> +		int level, bool line_status)
> +{
> +	return 0;
> +}
> -- 
> 2.7.3
> 

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

* [RFC PATCH 44/45] KVM: arm/arm64: vgic-new: Add dummy MSI implementation
@ 2016-03-31 18:16     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 18:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:05:07AM +0000, Andre Przywara wrote:
> Although we don't provide any virtual MSI functionality yet, we
> need to implement the functions required by the KVM interface.

I don't feel like this commit text accurately describes what's happening
in the code?

This seems to be about irqfds which work just fine on a GICv2m guest?

Thanks,
-Christoffer

> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic_irqfd.c | 51 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 51 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic_irqfd.c b/virt/kvm/arm/vgic/vgic_irqfd.c
> new file mode 100644
> index 0000000..3eee1bd
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic_irqfd.c
> @@ -0,0 +1,51 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * 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/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <trace/events/kvm.h>
> +
> +int kvm_irq_map_gsi(struct kvm *kvm,
> +		    struct kvm_kernel_irq_routing_entry *entries,
> +		    int gsi)
> +{
> +	return 0;
> +}
> +
> +int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
> +{
> +	return pin;
> +}
> +
> +int kvm_set_irq(struct kvm *kvm, int irq_source_id,
> +		u32 irq, int level, bool line_status)
> +{
> +	unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
> +
> +	trace_kvm_set_irq(irq, level, irq_source_id);
> +
> +	BUG_ON(!vgic_initialized(kvm));
> +
> +	return kvm_vgic_inject_irq(kvm, 0, spi, level);
> +}
> +
> +/* MSI not implemented yet */
> +int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
> +		struct kvm *kvm, int irq_source_id,
> +		int level, bool line_status)
> +{
> +	return 0;
> +}
> -- 
> 2.7.3
> 

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

* Re: [RFC PATCH 45/45] KVM: arm/arm64: vgic-new: enable build
  2016-03-25  2:05   ` Andre Przywara
@ 2016-03-31 18:18     ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 18:18 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, Mar 25, 2016 at 02:05:08AM +0000, Andre Przywara wrote:
> Now that the new VGIC implementation has reached feature parity with
> the old one, add the new files to the build system and add a Kconfig
> option to switch between the two versions.
> We set the default to the new version to get maximum test coverage,
> in case people experience problems they can switch back to the old
> behaviour if needed.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  arch/arm/kvm/Kconfig    |  7 +++++++
>  arch/arm/kvm/Makefile   | 10 ++++++++++
>  arch/arm64/kvm/Kconfig  |  7 +++++++
>  arch/arm64/kvm/Makefile | 10 ++++++++++
>  4 files changed, 34 insertions(+)
> 
> diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
> index 95a0005..02abfff 100644
> --- a/arch/arm/kvm/Kconfig
> +++ b/arch/arm/kvm/Kconfig
> @@ -46,6 +46,13 @@ config KVM_ARM_HOST
>  	---help---
>  	  Provides host support for ARM processors.
>  
> +config KVM_NEW_VGIC
> +	bool "New VGIC implementation"
> +	depends on KVM
> +	default y
> +	---help---
> +	  uses the new VGIC implementation
> +

I had imagined we'd name it in the reverse, so the option would have
been CONFIG_KVM_VGIC_LEGACY, but I guess the net effect should be the
same, assuming most people just go with the default anyway.

Thanks,
-Christoffer

>  source drivers/vhost/Kconfig
>  
>  endif # VIRTUALIZATION
> diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
> index eb1bf43..aa7d724 100644
> --- a/arch/arm/kvm/Makefile
> +++ b/arch/arm/kvm/Makefile
> @@ -21,7 +21,17 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp/
>  obj-y += kvm-arm.o init.o interrupts.o
>  obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
>  obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
> +
> +ifeq ($(CONFIG_KVM_NEW_VGIC),y)
> +obj-y += $(KVM)/arm/vgic/vgic.o
> +obj-y += $(KVM)/arm/vgic/vgic_init.o
> +obj-y += $(KVM)/arm/vgic/vgic_irqfd.o
> +obj-y += $(KVM)/arm/vgic/vgic-v2.o
> +obj-y += $(KVM)/arm/vgic/vgic_mmio.o
> +obj-y += $(KVM)/arm/vgic/vgic_kvm_device.o
> +else
>  obj-y += $(KVM)/arm/vgic.o
>  obj-y += $(KVM)/arm/vgic-v2.o
>  obj-y += $(KVM)/arm/vgic-v2-emul.o
> +endif
>  obj-y += $(KVM)/arm/arch_timer.o
> diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
> index de7450d..3f0e1ce 100644
> --- a/arch/arm64/kvm/Kconfig
> +++ b/arch/arm64/kvm/Kconfig
> @@ -55,6 +55,13 @@ config KVM_ARM_PMU
>  	  Adds support for a virtual Performance Monitoring Unit (PMU) in
>  	  virtual machines.
>  
> +config KVM_NEW_VGIC
> +	bool "New VGIC implementation"
> +	depends on KVM
> +	default y
> +        ---help---
> +          uses the new VGIC implementation
> +
>  source drivers/vhost/Kconfig
>  
>  endif # VIRTUALIZATION
> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
> index 122cff4..2f5d431 100644
> --- a/arch/arm64/kvm/Makefile
> +++ b/arch/arm64/kvm/Makefile
> @@ -20,10 +20,20 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
>  
> +ifeq ($(CONFIG_KVM_NEW_VGIC),y)
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_init.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_irqfd.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_mmio.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_kvm_device.o
> +else
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
> +endif
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
>  kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
> -- 
> 2.7.3
> 
> --
> 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] 276+ messages in thread

* [RFC PATCH 45/45] KVM: arm/arm64: vgic-new: enable build
@ 2016-03-31 18:18     ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 18:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:05:08AM +0000, Andre Przywara wrote:
> Now that the new VGIC implementation has reached feature parity with
> the old one, add the new files to the build system and add a Kconfig
> option to switch between the two versions.
> We set the default to the new version to get maximum test coverage,
> in case people experience problems they can switch back to the old
> behaviour if needed.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  arch/arm/kvm/Kconfig    |  7 +++++++
>  arch/arm/kvm/Makefile   | 10 ++++++++++
>  arch/arm64/kvm/Kconfig  |  7 +++++++
>  arch/arm64/kvm/Makefile | 10 ++++++++++
>  4 files changed, 34 insertions(+)
> 
> diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
> index 95a0005..02abfff 100644
> --- a/arch/arm/kvm/Kconfig
> +++ b/arch/arm/kvm/Kconfig
> @@ -46,6 +46,13 @@ config KVM_ARM_HOST
>  	---help---
>  	  Provides host support for ARM processors.
>  
> +config KVM_NEW_VGIC
> +	bool "New VGIC implementation"
> +	depends on KVM
> +	default y
> +	---help---
> +	  uses the new VGIC implementation
> +

I had imagined we'd name it in the reverse, so the option would have
been CONFIG_KVM_VGIC_LEGACY, but I guess the net effect should be the
same, assuming most people just go with the default anyway.

Thanks,
-Christoffer

>  source drivers/vhost/Kconfig
>  
>  endif # VIRTUALIZATION
> diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
> index eb1bf43..aa7d724 100644
> --- a/arch/arm/kvm/Makefile
> +++ b/arch/arm/kvm/Makefile
> @@ -21,7 +21,17 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp/
>  obj-y += kvm-arm.o init.o interrupts.o
>  obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
>  obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
> +
> +ifeq ($(CONFIG_KVM_NEW_VGIC),y)
> +obj-y += $(KVM)/arm/vgic/vgic.o
> +obj-y += $(KVM)/arm/vgic/vgic_init.o
> +obj-y += $(KVM)/arm/vgic/vgic_irqfd.o
> +obj-y += $(KVM)/arm/vgic/vgic-v2.o
> +obj-y += $(KVM)/arm/vgic/vgic_mmio.o
> +obj-y += $(KVM)/arm/vgic/vgic_kvm_device.o
> +else
>  obj-y += $(KVM)/arm/vgic.o
>  obj-y += $(KVM)/arm/vgic-v2.o
>  obj-y += $(KVM)/arm/vgic-v2-emul.o
> +endif
>  obj-y += $(KVM)/arm/arch_timer.o
> diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
> index de7450d..3f0e1ce 100644
> --- a/arch/arm64/kvm/Kconfig
> +++ b/arch/arm64/kvm/Kconfig
> @@ -55,6 +55,13 @@ config KVM_ARM_PMU
>  	  Adds support for a virtual Performance Monitoring Unit (PMU) in
>  	  virtual machines.
>  
> +config KVM_NEW_VGIC
> +	bool "New VGIC implementation"
> +	depends on KVM
> +	default y
> +        ---help---
> +          uses the new VGIC implementation
> +
>  source drivers/vhost/Kconfig
>  
>  endif # VIRTUALIZATION
> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
> index 122cff4..2f5d431 100644
> --- a/arch/arm64/kvm/Makefile
> +++ b/arch/arm64/kvm/Makefile
> @@ -20,10 +20,20 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
>  
> +ifeq ($(CONFIG_KVM_NEW_VGIC),y)
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_init.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_irqfd.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_mmio.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_kvm_device.o
> +else
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
> +endif
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
>  kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
> -- 
> 2.7.3
> 
> --
> 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] 276+ messages in thread

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-31 18:28   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 18:28 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

Hi Andre,

On Fri, Mar 25, 2016 at 02:04:23AM +0000, Andre Przywara wrote:
> This series is a joint effort to re-implement KVM's GIC emulation.
> 
> While the current implementation is centered around providing
> efficient MMIO emulation, the hot path for most guests is actually
> the guest entry and exit, which currently is rather costly.
> Also the existing emulation has a global distributor lock, which
> quickly becomes a bottleneck once the number of VCPUs increases.
> Additionally the emulation was originally designed for GICv2, adding
> GICv3 ITS emulation support to this proved to be rather painful.
> Last, but not least the existing code became less and less
> maintainable, with many special cases handled explicitly.
> 
> The new implementation is build around a struct vgic_irq data data
> structure, which holds all information about a virtual interrupt.
> Interruts which should be injected are hold in a per-VCPU list, this
> make the entry/exit path much more efficient. Also the new structure
> allows to have more fine grained locking - per IRQ and per VCPU -
> getting rid of the global distributor lock.
> As a result of the new design ITS emulation fits in more nicely, the
> respective code will be provided as a follow-up series.
> 
> This series implements the same feature set as the existing emulation,
> as a goodie we now implement priorities correctly.
> To allow an easy transition with good test coverage, but still maintain
> stability, both implementations live side by side, selectable via a
> Kconfig option. The default is the new implementation.
> If this code proves to be reliable, we will later remove the current
> implementation with an extra patch set.
> 
> Please have a look at the series, review it and give the code some
> serious testing (and possibly debugging). All feedback is appreciated.
> 

Huge thanks for all the hard work in putting this together, I'm sure it
hasn't been easy.

I have gone through this series and I think we're overall in pretty good
shape.  I haven't reviewed the code in detail, checked every bitfield
etc., but focused on the overall design choices, locking correctness
etc.

A number of patches don't have have commit message and some commit
messages could be clarified, but it is what it is.

I've given this a quick test on Mustang and on TC2, and it builds and
appears to run decently stable.  Obviously we should give this some more
rigorous testing, but I will wait until v2 with that.

I'll probably send the timer/vgic interface changes bits as patches for
you to base the next series on, assuming you and the others agreed with
my comments and suggestions on that part here.

Thanks,
-Christoffer

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-31 18:28   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 18:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andre,

On Fri, Mar 25, 2016 at 02:04:23AM +0000, Andre Przywara wrote:
> This series is a joint effort to re-implement KVM's GIC emulation.
> 
> While the current implementation is centered around providing
> efficient MMIO emulation, the hot path for most guests is actually
> the guest entry and exit, which currently is rather costly.
> Also the existing emulation has a global distributor lock, which
> quickly becomes a bottleneck once the number of VCPUs increases.
> Additionally the emulation was originally designed for GICv2, adding
> GICv3 ITS emulation support to this proved to be rather painful.
> Last, but not least the existing code became less and less
> maintainable, with many special cases handled explicitly.
> 
> The new implementation is build around a struct vgic_irq data data
> structure, which holds all information about a virtual interrupt.
> Interruts which should be injected are hold in a per-VCPU list, this
> make the entry/exit path much more efficient. Also the new structure
> allows to have more fine grained locking - per IRQ and per VCPU -
> getting rid of the global distributor lock.
> As a result of the new design ITS emulation fits in more nicely, the
> respective code will be provided as a follow-up series.
> 
> This series implements the same feature set as the existing emulation,
> as a goodie we now implement priorities correctly.
> To allow an easy transition with good test coverage, but still maintain
> stability, both implementations live side by side, selectable via a
> Kconfig option. The default is the new implementation.
> If this code proves to be reliable, we will later remove the current
> implementation with an extra patch set.
> 
> Please have a look at the series, review it and give the code some
> serious testing (and possibly debugging). All feedback is appreciated.
> 

Huge thanks for all the hard work in putting this together, I'm sure it
hasn't been easy.

I have gone through this series and I think we're overall in pretty good
shape.  I haven't reviewed the code in detail, checked every bitfield
etc., but focused on the overall design choices, locking correctness
etc.

A number of patches don't have have commit message and some commit
messages could be clarified, but it is what it is.

I've given this a quick test on Mustang and on TC2, and it builds and
appears to run decently stable.  Obviously we should give this some more
rigorous testing, but I will wait until v2 with that.

I'll probably send the timer/vgic interface changes bits as patches for
you to base the next series on, assuming you and the others agreed with
my comments and suggestions on that part here.

Thanks,
-Christoffer

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-25  2:04 ` Andre Przywara
@ 2016-03-31 18:30   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 18:30 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, Mar 25, 2016 at 02:04:23AM +0000, Andre Przywara wrote:
> This series is a joint effort to re-implement KVM's GIC emulation.
> 
> While the current implementation is centered around providing
> efficient MMIO emulation, the hot path for most guests is actually
> the guest entry and exit, which currently is rather costly.
> Also the existing emulation has a global distributor lock, which
> quickly becomes a bottleneck once the number of VCPUs increases.
> Additionally the emulation was originally designed for GICv2, adding
> GICv3 ITS emulation support to this proved to be rather painful.
> Last, but not least the existing code became less and less
> maintainable, with many special cases handled explicitly.
> 
> The new implementation is build around a struct vgic_irq data data
> structure, which holds all information about a virtual interrupt.
> Interruts which should be injected are hold in a per-VCPU list, this
> make the entry/exit path much more efficient. Also the new structure
> allows to have more fine grained locking - per IRQ and per VCPU -
> getting rid of the global distributor lock.
> As a result of the new design ITS emulation fits in more nicely, the
> respective code will be provided as a follow-up series.
> 
> This series implements the same feature set as the existing emulation,
> as a goodie we now implement priorities correctly.
> To allow an easy transition with good test coverage, but still maintain
> stability, both implementations live side by side, selectable via a
> Kconfig option. The default is the new implementation.
> If this code proves to be reliable, we will later remove the current
> implementation with an extra patch set.
> 
> Please have a look at the series, review it and give the code some
> serious testing (and possibly debugging). All feedback is appreciated.
> 

Hmph, starting a guest a couple of times and running hackbench inside
the guest actually gave me (twice) the following error:

NMI watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [kworker/0:0:4]

(that is using your branch on Mustang).

-Christoffer

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-03-31 18:30   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-03-31 18:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 25, 2016 at 02:04:23AM +0000, Andre Przywara wrote:
> This series is a joint effort to re-implement KVM's GIC emulation.
> 
> While the current implementation is centered around providing
> efficient MMIO emulation, the hot path for most guests is actually
> the guest entry and exit, which currently is rather costly.
> Also the existing emulation has a global distributor lock, which
> quickly becomes a bottleneck once the number of VCPUs increases.
> Additionally the emulation was originally designed for GICv2, adding
> GICv3 ITS emulation support to this proved to be rather painful.
> Last, but not least the existing code became less and less
> maintainable, with many special cases handled explicitly.
> 
> The new implementation is build around a struct vgic_irq data data
> structure, which holds all information about a virtual interrupt.
> Interruts which should be injected are hold in a per-VCPU list, this
> make the entry/exit path much more efficient. Also the new structure
> allows to have more fine grained locking - per IRQ and per VCPU -
> getting rid of the global distributor lock.
> As a result of the new design ITS emulation fits in more nicely, the
> respective code will be provided as a follow-up series.
> 
> This series implements the same feature set as the existing emulation,
> as a goodie we now implement priorities correctly.
> To allow an easy transition with good test coverage, but still maintain
> stability, both implementations live side by side, selectable via a
> Kconfig option. The default is the new implementation.
> If this code proves to be reliable, we will later remove the current
> implementation with an extra patch set.
> 
> Please have a look at the series, review it and give the code some
> serious testing (and possibly debugging). All feedback is appreciated.
> 

Hmph, starting a guest a couple of times and running hackbench inside
the guest actually gave me (twice) the following error:

NMI watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [kworker/0:0:4]

(that is using your branch on Mustang).

-Christoffer

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

* Re: [RFC PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
  2016-03-31 17:59     ` Christoffer Dall
@ 2016-04-01  8:20       ` Eric Auger
  -1 siblings, 0 replies; 276+ messages in thread
From: Eric Auger @ 2016-04-01  8:20 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara
  Cc: Marc Zyngier, kvmarm, kvm, linux-arm-kernel

Hi Christoffer,
On 03/31/2016 07:59 PM, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:05:03AM +0000, Andre Przywara wrote:
>> From: Eric Auger <eric.auger@linaro.org>
>>
>> This patch allocates and initializes the data structures used
>> to model the vgic distributor and virtual cpu interfaces. At that
>> stage the number of IRQs and number of virtual CPUs is frozen.
>>
>> The following realy_init functions are kept since they are called from
>> arm.c. However they may disappear in subsequent patches since
>> they are void.
>>
>> vgic_[v2|v3]_enable still is stubbed at this stage.
> 
> early init ?
Indeed I can mention those functions also are stubbed. Eventually it may
make sense to remove their call from arm.c but this was not done yet in
this series to avoid touching non vgic code.
> 
>>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h       |   7 +-
>>  virt/kvm/arm/vgic/vgic-v2.c   |   5 +
>>  virt/kvm/arm/vgic/vgic-v3.c   |   5 +
>>  virt/kvm/arm/vgic/vgic.c      |   5 +
>>  virt/kvm/arm/vgic/vgic.h      |   8 ++
>>  virt/kvm/arm/vgic/vgic_init.c | 214 ++++++++++++++++++++++++++++++++++++++++++
>>  6 files changed, 243 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 536582b..4a51582 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -115,6 +115,7 @@ struct vgic_io_device {
>>  struct vgic_dist {
>>  	bool			in_kernel;
>>  	bool			ready;
>> +	bool			initialized;
>>  
>>  	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>>  	u32			vgic_model;
>> @@ -195,7 +196,11 @@ struct vgic_cpu {
>>  };
>>  
>>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
>> +void kvm_vgic_early_init(struct kvm *kvm);
>>  int kvm_vgic_create(struct kvm *kvm, u32 type);
>> +void kvm_vgic_destroy(struct kvm *kvm);
>> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
>>  int kvm_vgic_hyp_init(void);
>>  
>>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>> @@ -204,7 +209,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>>  
>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>> -#define vgic_initialized(k)	(false)
>> +#define vgic_initialized(k)	((k)->arch.vgic.initialized)
>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>> index 0cb5c4f..c48dbd4 100644
>> --- a/virt/kvm/arm/vgic/vgic-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>> @@ -234,6 +234,11 @@ void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>>  	spin_unlock(&irq->irq_lock);
>>  }
>>  
>> +/* not yet implemented */
>> +void vgic_v2_enable(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>>  /**
>>   * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
>>   * @node:	pointer to the DT node
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index 1a53141..3155680 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -220,6 +220,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>>  }
>>  
>> +/* not yet implemented */
>> +void vgic_v3_enable(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>>  /**
>>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>>   * @node:	pointer to the DT node
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 8c19379..4ade7c0 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -268,6 +268,11 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  			bool level)
>>  {
>>  	struct kvm_vcpu *vcpu;
>> +	int ret;
>> +
>> +	ret = vgic_lazy_init(kvm);
>> +	if (ret)
>> +		return ret;
>>  
>>  	vcpu = kvm_get_vcpu(kvm, cpuid);
>>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 31c9299a..4b2e1b0 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -38,6 +38,7 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>> +void vgic_v2_enable(struct kvm_vcpu *vcpu);
>>  int vgic_v2_probe(struct device_node *vgic_node);
>>  
>>  #ifdef CONFIG_KVM_ARM_VGIC_V3
>> @@ -52,6 +53,7 @@ int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
>>  			  int offset, int len, void *val);
>>  void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>> +void vgic_v3_enable(struct kvm_vcpu *vcpu);
>>  int vgic_v3_probe(struct device_node *vgic_node);
>>  #else
>>  static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
>> @@ -98,6 +100,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>>  {
>>  }
>>  
>> +static inline void vgic_v3_enable(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>>  static inline int vgic_v3_probe(struct device_node *vgic_node)
>>  {
>>  	return -ENODEV;
>> @@ -107,6 +113,8 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
>>  void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  
>> +int vgic_lazy_init(struct kvm *kvm);
>> +int vgic_init(struct kvm *kvm);
>>  void kvm_register_vgic_device(unsigned long type);
>>  
>>  #endif
>> diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
>> index 80bf283..f7a6a11 100644
>> --- a/virt/kvm/arm/vgic/vgic_init.c
>> +++ b/virt/kvm/arm/vgic/vgic_init.c
>> @@ -24,6 +24,42 @@
>>  #include <asm/kvm_mmu.h>
>>  #include "vgic.h"
>>  
>> +/*
>> + * Initialization rules: there are multiple stages to the vgic
>> + * initialization, both for the distributor and the CPU interfaces.
>> + *
>> + * Distributor:
>> + *
>> + * - kvm_vgic_early_init(): initialization of static data that doesn't
>> + *   depend on any sizing information or emulation type. No allocation
>> + *   is allowed there.
>> + *
>> + * - vgic_init(): allocation and initialization of the generic data
>> + *   structures that depend on sizing information (number of CPUs,
>> + *   number of interrupts). Also initializes the vcpu specific data
>> + *   structures. Can be executed lazily for GICv2.
>> + *
>> + * CPU Interface:
>> + *
>> + * - kvm_vgic_cpu_early_init(): initialization of static data that
>> + *   doesn't depend on any sizing information or emulation type. No
>> + *   allocation is allowed there.
>> + */
>> +
>> +/* EARLY INIT */
>> +
>> +/*
>> + * Those 2 functions should not be needed anymore but they
>> + * still are called from arm.c
>> + */
>> +void kvm_vgic_early_init(struct kvm *kvm)
>> +{
>> +}
>> +
>> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>>  /* CREATION */
>>  
>>  /**
>> @@ -108,6 +144,184 @@ out:
>>  	return ret;
>>  }
>>  
>> +/* INIT/DESTROY */
>> +
>> +/**
>> + * kvm_vgic_dist_init: initialize the dist data structures
>> + * @kvm: kvm struct pointer
>> + * @nr_spis: number of spis, frozen by caller
>> + */
>> +int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +	int i;
>> +
>> +	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
>> +	if (!dist->spis)
>> +		return  -ENOMEM;
>> +
>> +	/*
>> +	 * In following code we do not take the irq struct lock since
>> +	 * no other action on irq structs can happen while the VGIC is
>> +	 * not initialized yet:
>> +	 * injection requires (VGICV3) or does (VGIC2) initialization.
>> +	 * MMIO access triggers init.
>> +	 */
>> +	for (i = 0; i < nr_spis; i++) {
>> +		struct vgic_irq *irq = &dist->spis[i];
>> +
>> +		irq->intid = i + VGIC_NR_PRIVATE_IRQS;
>> +		INIT_LIST_HEAD(&irq->ap_list);
>> +		spin_lock_init(&irq->irq_lock);
>> +		irq->vcpu = NULL;
>> +		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
>> +			vgic_v2_irq_change_affinity(kvm, irq->intid, 0);
>> +		else
>> +			vgic_v3_irq_change_affinity(kvm, irq->intid, 0);
>> +	}
>> +	return 0;
>> +}
>> +
>> +/**
>> + * kvm_vgic_vcpu_init: initialize the vcpu data structures and
>> + * enable the VCPU interface
>> + * @kvm: kvm struct pointer
>> + */
>> +void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	int i;
>> +
>> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
>> +	spin_lock_init(&vgic_cpu->ap_list_lock);
>> +	vgic_cpu->nr_lr = kvm_vgic_global_state.nr_lr;
>> +
>> +	/*
>> +	 * Enable and configure all SGIs to be edge-triggered and
>> +	 * configure all PPIs as level-triggered.
>> +	 */
>> +	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
>> +		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
>> +
>> +		INIT_LIST_HEAD(&irq->ap_list);
> 
> I don't think this is strictly required, but ok.
agreed

Best Regards

Eric

> 
>> +		spin_lock_init(&irq->irq_lock);
>> +		irq->intid = i;
>> +		irq->vcpu = NULL;
>> +		irq->target_vcpu = vcpu;
>> +		irq->targets = 1U << vcpu->vcpu_id;
>> +		if (i < VGIC_NR_SGIS) {
>> +			/* SGIs */
>> +			irq->enabled = 1;
>> +			irq->config = VGIC_CONFIG_EDGE;
>> +		} else {
>> +			/* PPIs */
>> +			irq->config = VGIC_CONFIG_LEVEL;
>> +		}
>> +	}
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_enable(vcpu);
>> +	else
>> +		vgic_v3_enable(vcpu);
>> +}
>> +
>> +/*
>> + * vgic_init: allocates and initializes dist and vcpu data structures
>> + * depending on two dimensioning parameters:
>> + * - the number of spis
>> + * - the number of vcpus
>> + * The function is generally called when nr_spis has been explicitly set
>> + * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
>> + * Completion can be tested by vgic_initialized
>> + * Must be called with kvm->lock held!
>> + */
>> +int vgic_init(struct kvm *kvm)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +	struct kvm_vcpu *vcpu;
>> +	int ret = 0, i;
>> +
>> +	if (vgic_initialized(kvm))
>> +		return 0;
>> +
>> +	/* freeze the number of spis */
>> +	if (!dist->nr_spis)
>> +		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
>> +
>> +	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
>> +	if (ret)
>> +		goto out;
>> +
>> +	kvm_for_each_vcpu(i, vcpu, kvm)
>> +		kvm_vgic_vcpu_init(vcpu);
>> +
>> +	dist->initialized = true;
>> +out:
>> +	return ret;
>> +}
>> +
>> +static void kvm_vgic_dist_destroy(struct kvm *kvm)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +
>> +	mutex_lock(&kvm->lock);
>> +
>> +	dist->ready = false;
>> +	dist->initialized = false;
>> +
>> +	kfree(dist->spis);
>> +	kfree(dist->dist_iodevs);
>> +	kfree(dist->redist_iodevs);
>> +	dist->nr_spis = 0;
>> +
>> +	mutex_unlock(&kvm->lock);
>> +}
>> +
>> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +
>> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
>> +	vgic_cpu->nr_lr = 0;
>> +}
>> +
>> +void kvm_vgic_destroy(struct kvm *kvm)
>> +{
>> +	struct kvm_vcpu *vcpu;
>> +	int i;
>> +
>> +	kvm_vgic_dist_destroy(kvm);
>> +
>> +	kvm_for_each_vcpu(i, vcpu, kvm)
>> +		kvm_vgic_vcpu_destroy(vcpu);
>> +}
>> +
>> +/**
>> + * Lazy init only is allowed if the GIC exposed to the guest is a GICV2.
>> + * GICV3 must be explicitly initialized by the guest using the
>> + * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group
>> + */
>> +int vgic_lazy_init(struct kvm *kvm)
>> +{
>> +	int ret = 0;
>> +
>> +	if (unlikely(!vgic_initialized(kvm))) {
>> +		/*
>> +		 * We only provide the automatic initialization of the VGIC
>> +		 * for the legacy case of a GICv2. Any other type must
>> +		 * be explicitly initialized once setup with the respective
>> +		 * KVM device call.
>> +		 */
>> +		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
>> +			return -EBUSY;
>> +
>> +		mutex_lock(&kvm->lock);
>> +		ret = vgic_init(kvm);
>> +		mutex_unlock(&kvm->lock);
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>>  /* GENERIC PROBE */
>>  
>>  static void vgic_init_maintenance_interrupt(void *info)
>> -- 
>> 2.7.3
>>


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

* [RFC PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
@ 2016-04-01  8:20       ` Eric Auger
  0 siblings, 0 replies; 276+ messages in thread
From: Eric Auger @ 2016-04-01  8:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,
On 03/31/2016 07:59 PM, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:05:03AM +0000, Andre Przywara wrote:
>> From: Eric Auger <eric.auger@linaro.org>
>>
>> This patch allocates and initializes the data structures used
>> to model the vgic distributor and virtual cpu interfaces. At that
>> stage the number of IRQs and number of virtual CPUs is frozen.
>>
>> The following realy_init functions are kept since they are called from
>> arm.c. However they may disappear in subsequent patches since
>> they are void.
>>
>> vgic_[v2|v3]_enable still is stubbed at this stage.
> 
> early init ?
Indeed I can mention those functions also are stubbed. Eventually it may
make sense to remove their call from arm.c but this was not done yet in
this series to avoid touching non vgic code.
> 
>>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h       |   7 +-
>>  virt/kvm/arm/vgic/vgic-v2.c   |   5 +
>>  virt/kvm/arm/vgic/vgic-v3.c   |   5 +
>>  virt/kvm/arm/vgic/vgic.c      |   5 +
>>  virt/kvm/arm/vgic/vgic.h      |   8 ++
>>  virt/kvm/arm/vgic/vgic_init.c | 214 ++++++++++++++++++++++++++++++++++++++++++
>>  6 files changed, 243 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 536582b..4a51582 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -115,6 +115,7 @@ struct vgic_io_device {
>>  struct vgic_dist {
>>  	bool			in_kernel;
>>  	bool			ready;
>> +	bool			initialized;
>>  
>>  	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>>  	u32			vgic_model;
>> @@ -195,7 +196,11 @@ struct vgic_cpu {
>>  };
>>  
>>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
>> +void kvm_vgic_early_init(struct kvm *kvm);
>>  int kvm_vgic_create(struct kvm *kvm, u32 type);
>> +void kvm_vgic_destroy(struct kvm *kvm);
>> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
>>  int kvm_vgic_hyp_init(void);
>>  
>>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>> @@ -204,7 +209,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>>  
>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>> -#define vgic_initialized(k)	(false)
>> +#define vgic_initialized(k)	((k)->arch.vgic.initialized)
>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>> index 0cb5c4f..c48dbd4 100644
>> --- a/virt/kvm/arm/vgic/vgic-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>> @@ -234,6 +234,11 @@ void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>>  	spin_unlock(&irq->irq_lock);
>>  }
>>  
>> +/* not yet implemented */
>> +void vgic_v2_enable(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>>  /**
>>   * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
>>   * @node:	pointer to the DT node
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index 1a53141..3155680 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -220,6 +220,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>>  }
>>  
>> +/* not yet implemented */
>> +void vgic_v3_enable(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>>  /**
>>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>>   * @node:	pointer to the DT node
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 8c19379..4ade7c0 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -268,6 +268,11 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  			bool level)
>>  {
>>  	struct kvm_vcpu *vcpu;
>> +	int ret;
>> +
>> +	ret = vgic_lazy_init(kvm);
>> +	if (ret)
>> +		return ret;
>>  
>>  	vcpu = kvm_get_vcpu(kvm, cpuid);
>>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 31c9299a..4b2e1b0 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -38,6 +38,7 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>> +void vgic_v2_enable(struct kvm_vcpu *vcpu);
>>  int vgic_v2_probe(struct device_node *vgic_node);
>>  
>>  #ifdef CONFIG_KVM_ARM_VGIC_V3
>> @@ -52,6 +53,7 @@ int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
>>  			  int offset, int len, void *val);
>>  void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>> +void vgic_v3_enable(struct kvm_vcpu *vcpu);
>>  int vgic_v3_probe(struct device_node *vgic_node);
>>  #else
>>  static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
>> @@ -98,6 +100,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>>  {
>>  }
>>  
>> +static inline void vgic_v3_enable(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>>  static inline int vgic_v3_probe(struct device_node *vgic_node)
>>  {
>>  	return -ENODEV;
>> @@ -107,6 +113,8 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
>>  void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  
>> +int vgic_lazy_init(struct kvm *kvm);
>> +int vgic_init(struct kvm *kvm);
>>  void kvm_register_vgic_device(unsigned long type);
>>  
>>  #endif
>> diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
>> index 80bf283..f7a6a11 100644
>> --- a/virt/kvm/arm/vgic/vgic_init.c
>> +++ b/virt/kvm/arm/vgic/vgic_init.c
>> @@ -24,6 +24,42 @@
>>  #include <asm/kvm_mmu.h>
>>  #include "vgic.h"
>>  
>> +/*
>> + * Initialization rules: there are multiple stages to the vgic
>> + * initialization, both for the distributor and the CPU interfaces.
>> + *
>> + * Distributor:
>> + *
>> + * - kvm_vgic_early_init(): initialization of static data that doesn't
>> + *   depend on any sizing information or emulation type. No allocation
>> + *   is allowed there.
>> + *
>> + * - vgic_init(): allocation and initialization of the generic data
>> + *   structures that depend on sizing information (number of CPUs,
>> + *   number of interrupts). Also initializes the vcpu specific data
>> + *   structures. Can be executed lazily for GICv2.
>> + *
>> + * CPU Interface:
>> + *
>> + * - kvm_vgic_cpu_early_init(): initialization of static data that
>> + *   doesn't depend on any sizing information or emulation type. No
>> + *   allocation is allowed there.
>> + */
>> +
>> +/* EARLY INIT */
>> +
>> +/*
>> + * Those 2 functions should not be needed anymore but they
>> + * still are called from arm.c
>> + */
>> +void kvm_vgic_early_init(struct kvm *kvm)
>> +{
>> +}
>> +
>> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>>  /* CREATION */
>>  
>>  /**
>> @@ -108,6 +144,184 @@ out:
>>  	return ret;
>>  }
>>  
>> +/* INIT/DESTROY */
>> +
>> +/**
>> + * kvm_vgic_dist_init: initialize the dist data structures
>> + * @kvm: kvm struct pointer
>> + * @nr_spis: number of spis, frozen by caller
>> + */
>> +int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +	int i;
>> +
>> +	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
>> +	if (!dist->spis)
>> +		return  -ENOMEM;
>> +
>> +	/*
>> +	 * In following code we do not take the irq struct lock since
>> +	 * no other action on irq structs can happen while the VGIC is
>> +	 * not initialized yet:
>> +	 * injection requires (VGICV3) or does (VGIC2) initialization.
>> +	 * MMIO access triggers init.
>> +	 */
>> +	for (i = 0; i < nr_spis; i++) {
>> +		struct vgic_irq *irq = &dist->spis[i];
>> +
>> +		irq->intid = i + VGIC_NR_PRIVATE_IRQS;
>> +		INIT_LIST_HEAD(&irq->ap_list);
>> +		spin_lock_init(&irq->irq_lock);
>> +		irq->vcpu = NULL;
>> +		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
>> +			vgic_v2_irq_change_affinity(kvm, irq->intid, 0);
>> +		else
>> +			vgic_v3_irq_change_affinity(kvm, irq->intid, 0);
>> +	}
>> +	return 0;
>> +}
>> +
>> +/**
>> + * kvm_vgic_vcpu_init: initialize the vcpu data structures and
>> + * enable the VCPU interface
>> + * @kvm: kvm struct pointer
>> + */
>> +void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	int i;
>> +
>> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
>> +	spin_lock_init(&vgic_cpu->ap_list_lock);
>> +	vgic_cpu->nr_lr = kvm_vgic_global_state.nr_lr;
>> +
>> +	/*
>> +	 * Enable and configure all SGIs to be edge-triggered and
>> +	 * configure all PPIs as level-triggered.
>> +	 */
>> +	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
>> +		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
>> +
>> +		INIT_LIST_HEAD(&irq->ap_list);
> 
> I don't think this is strictly required, but ok.
agreed

Best Regards

Eric

> 
>> +		spin_lock_init(&irq->irq_lock);
>> +		irq->intid = i;
>> +		irq->vcpu = NULL;
>> +		irq->target_vcpu = vcpu;
>> +		irq->targets = 1U << vcpu->vcpu_id;
>> +		if (i < VGIC_NR_SGIS) {
>> +			/* SGIs */
>> +			irq->enabled = 1;
>> +			irq->config = VGIC_CONFIG_EDGE;
>> +		} else {
>> +			/* PPIs */
>> +			irq->config = VGIC_CONFIG_LEVEL;
>> +		}
>> +	}
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_enable(vcpu);
>> +	else
>> +		vgic_v3_enable(vcpu);
>> +}
>> +
>> +/*
>> + * vgic_init: allocates and initializes dist and vcpu data structures
>> + * depending on two dimensioning parameters:
>> + * - the number of spis
>> + * - the number of vcpus
>> + * The function is generally called when nr_spis has been explicitly set
>> + * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
>> + * Completion can be tested by vgic_initialized
>> + * Must be called with kvm->lock held!
>> + */
>> +int vgic_init(struct kvm *kvm)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +	struct kvm_vcpu *vcpu;
>> +	int ret = 0, i;
>> +
>> +	if (vgic_initialized(kvm))
>> +		return 0;
>> +
>> +	/* freeze the number of spis */
>> +	if (!dist->nr_spis)
>> +		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
>> +
>> +	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
>> +	if (ret)
>> +		goto out;
>> +
>> +	kvm_for_each_vcpu(i, vcpu, kvm)
>> +		kvm_vgic_vcpu_init(vcpu);
>> +
>> +	dist->initialized = true;
>> +out:
>> +	return ret;
>> +}
>> +
>> +static void kvm_vgic_dist_destroy(struct kvm *kvm)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +
>> +	mutex_lock(&kvm->lock);
>> +
>> +	dist->ready = false;
>> +	dist->initialized = false;
>> +
>> +	kfree(dist->spis);
>> +	kfree(dist->dist_iodevs);
>> +	kfree(dist->redist_iodevs);
>> +	dist->nr_spis = 0;
>> +
>> +	mutex_unlock(&kvm->lock);
>> +}
>> +
>> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +
>> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
>> +	vgic_cpu->nr_lr = 0;
>> +}
>> +
>> +void kvm_vgic_destroy(struct kvm *kvm)
>> +{
>> +	struct kvm_vcpu *vcpu;
>> +	int i;
>> +
>> +	kvm_vgic_dist_destroy(kvm);
>> +
>> +	kvm_for_each_vcpu(i, vcpu, kvm)
>> +		kvm_vgic_vcpu_destroy(vcpu);
>> +}
>> +
>> +/**
>> + * Lazy init only is allowed if the GIC exposed to the guest is a GICV2.
>> + * GICV3 must be explicitly initialized by the guest using the
>> + * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group
>> + */
>> +int vgic_lazy_init(struct kvm *kvm)
>> +{
>> +	int ret = 0;
>> +
>> +	if (unlikely(!vgic_initialized(kvm))) {
>> +		/*
>> +		 * We only provide the automatic initialization of the VGIC
>> +		 * for the legacy case of a GICv2. Any other type must
>> +		 * be explicitly initialized once setup with the respective
>> +		 * KVM device call.
>> +		 */
>> +		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
>> +			return -EBUSY;
>> +
>> +		mutex_lock(&kvm->lock);
>> +		ret = vgic_init(kvm);
>> +		mutex_unlock(&kvm->lock);
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>>  /* GENERIC PROBE */
>>  
>>  static void vgic_init_maintenance_interrupt(void *info)
>> -- 
>> 2.7.3
>>

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

* Re: [RFC PATCH 43/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
  2016-03-31 18:15     ` Christoffer Dall
@ 2016-04-01  8:44       ` Eric Auger
  -1 siblings, 0 replies; 276+ messages in thread
From: Eric Auger @ 2016-04-01  8:44 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara
  Cc: Marc Zyngier, kvmarm, kvm, linux-arm-kernel

On 03/31/2016 08:15 PM, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:05:06AM +0000, Andre Przywara wrote:
>> We now store the mapped hardware IRQ number in our struct, so we
>> don't need the irq_phys_map any longer for the new VGIC.
>> Implement the hardware IRQ mapping on top of the reworked arch
>> timer interface.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h  | 15 ++++++++
>>  virt/kvm/arm/vgic/vgic.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 107 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index e418de9..7c1d145 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -206,6 +206,21 @@ int kvm_vgic_hyp_init(void);
>>  
>>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  			bool level);
>> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>> +			       bool level);
>> +
>> +/*
>> + * This is not really needed, but we need this type to keep the arch
>> + * timer compatible with the old VGIC implementation.
>> + * This should be removed upon retiring the old VGIC.
>> + */
>> +struct irq_phys_map {};
>> +
>> +struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
>> +					   u32 virt_irq, u32 irq);
>> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
>> +			    u32 intid);
>> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid);
>>  
>>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>>  
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 4ade7c0..65395af 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -17,6 +17,9 @@
>>  #include <linux/kvm.h>
>>  #include <linux/kvm_host.h>
>>  #include <linux/list_sort.h>
>> +#include <linux/irq.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irqdesc.h>
>>  
>>  #include "vgic.h"
>>  
>> @@ -276,6 +279,83 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  
>>  	vcpu = kvm_get_vcpu(kvm, cpuid);
>>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * kvm_vgic_inject_mapped_irq - Inject a hardware mapped IRQ to the vgic
>> + * @kvm:     The VM structure pointer
>> + * @cpuid:   The CPU for PPIs
>> + * @irq_num: The INTID to inject a new state to.
>> + * @level:   Edge-triggered:  true:  to trigger the interrupt
>> + *			      false: to ignore the call
>> + *	     Level-sensitive  true:  raise the input signal
>> + *			      false: lower the input signal
>> + *
>> + * The GIC is not concerned with devices being active-LOW or active-HIGH for
>> + * level-sensitive interrupts.  You can think of the level parameter as 1
>> + * being HIGH and 0 being LOW and all devices being active-HIGH.
>> + */
>> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>> +			       bool level)
>> +{
>> +	struct kvm_vcpu *vcpu;
>> +	int ret;
>> +
>> +	ret = vgic_lazy_init(kvm);
>> +	if (ret)
>> +		return ret;
>> +
>> +	vcpu = kvm_get_vcpu(kvm, cpuid);
>> +	vgic_update_irq_pending(kvm, vcpu, intid, level);
>> +
>> +	return 0;
>> +}
>> +
>> +struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
>> +					   u32 virt_irq, u32 intid)
>> +{
>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
>> +	struct irq_desc *desc;
>> +	struct irq_data *data;
>> +
>> +	BUG_ON(!irq);
>> +
>> +	desc = irq_to_desc(intid);
> 
> eh, but that's not an INTID, that's a linux IRQ number then right?
agreed. Also the declaration suggested it is a linux irq.

Eric
> 
>> +	if (!desc) {
>> +		kvm_err("%s: no interrupt descriptor\n", __func__);
>> +		return NULL;
>> +	}
>> +
>> +	data = irq_desc_get_irq_data(desc);
>> +	while (data->parent_data)
>> +		data = data->parent_data;
>> +
>> +	spin_lock(&irq->irq_lock);
>> +
>> +	irq->hw = true;
>> +	irq->hwintid = data->hwirq;
>> +
>> +	spin_unlock(&irq->irq_lock);
>> +
>> +	return NULL;
>> +}
>> +
>> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
>> +			    u32 intid)
>> +{
>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +	BUG_ON(!irq);
>> +
>> +	spin_lock(&irq->irq_lock);
>> +
>> +	irq->hw = false;
>> +	irq->hwintid = 0;
>> +
>> +	spin_unlock(&irq->irq_lock);
>> +
>>  	return 0;
>>  }
>>  
>> @@ -520,3 +600,15 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
>>  
>>  	return pending;
>>  }
>> +
>> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid)
>> +{
>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +	bool map_is_active;
>> +
>> +	spin_lock(&irq->irq_lock);
>> +	map_is_active = irq->hw && irq->active;
>> +	spin_unlock(&irq->irq_lock);
>> +
>> +	return map_is_active;
>> +}
>> -- 
>> 2.7.3
>>
>> --
>> 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] 276+ messages in thread

* [RFC PATCH 43/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
@ 2016-04-01  8:44       ` Eric Auger
  0 siblings, 0 replies; 276+ messages in thread
From: Eric Auger @ 2016-04-01  8:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/31/2016 08:15 PM, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:05:06AM +0000, Andre Przywara wrote:
>> We now store the mapped hardware IRQ number in our struct, so we
>> don't need the irq_phys_map any longer for the new VGIC.
>> Implement the hardware IRQ mapping on top of the reworked arch
>> timer interface.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h  | 15 ++++++++
>>  virt/kvm/arm/vgic/vgic.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 107 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index e418de9..7c1d145 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -206,6 +206,21 @@ int kvm_vgic_hyp_init(void);
>>  
>>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  			bool level);
>> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>> +			       bool level);
>> +
>> +/*
>> + * This is not really needed, but we need this type to keep the arch
>> + * timer compatible with the old VGIC implementation.
>> + * This should be removed upon retiring the old VGIC.
>> + */
>> +struct irq_phys_map {};
>> +
>> +struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
>> +					   u32 virt_irq, u32 irq);
>> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
>> +			    u32 intid);
>> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid);
>>  
>>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>>  
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 4ade7c0..65395af 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -17,6 +17,9 @@
>>  #include <linux/kvm.h>
>>  #include <linux/kvm_host.h>
>>  #include <linux/list_sort.h>
>> +#include <linux/irq.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irqdesc.h>
>>  
>>  #include "vgic.h"
>>  
>> @@ -276,6 +279,83 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  
>>  	vcpu = kvm_get_vcpu(kvm, cpuid);
>>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * kvm_vgic_inject_mapped_irq - Inject a hardware mapped IRQ to the vgic
>> + * @kvm:     The VM structure pointer
>> + * @cpuid:   The CPU for PPIs
>> + * @irq_num: The INTID to inject a new state to.
>> + * @level:   Edge-triggered:  true:  to trigger the interrupt
>> + *			      false: to ignore the call
>> + *	     Level-sensitive  true:  raise the input signal
>> + *			      false: lower the input signal
>> + *
>> + * The GIC is not concerned with devices being active-LOW or active-HIGH for
>> + * level-sensitive interrupts.  You can think of the level parameter as 1
>> + * being HIGH and 0 being LOW and all devices being active-HIGH.
>> + */
>> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>> +			       bool level)
>> +{
>> +	struct kvm_vcpu *vcpu;
>> +	int ret;
>> +
>> +	ret = vgic_lazy_init(kvm);
>> +	if (ret)
>> +		return ret;
>> +
>> +	vcpu = kvm_get_vcpu(kvm, cpuid);
>> +	vgic_update_irq_pending(kvm, vcpu, intid, level);
>> +
>> +	return 0;
>> +}
>> +
>> +struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
>> +					   u32 virt_irq, u32 intid)
>> +{
>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
>> +	struct irq_desc *desc;
>> +	struct irq_data *data;
>> +
>> +	BUG_ON(!irq);
>> +
>> +	desc = irq_to_desc(intid);
> 
> eh, but that's not an INTID, that's a linux IRQ number then right?
agreed. Also the declaration suggested it is a linux irq.

Eric
> 
>> +	if (!desc) {
>> +		kvm_err("%s: no interrupt descriptor\n", __func__);
>> +		return NULL;
>> +	}
>> +
>> +	data = irq_desc_get_irq_data(desc);
>> +	while (data->parent_data)
>> +		data = data->parent_data;
>> +
>> +	spin_lock(&irq->irq_lock);
>> +
>> +	irq->hw = true;
>> +	irq->hwintid = data->hwirq;
>> +
>> +	spin_unlock(&irq->irq_lock);
>> +
>> +	return NULL;
>> +}
>> +
>> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map,
>> +			    u32 intid)
>> +{
>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +	BUG_ON(!irq);
>> +
>> +	spin_lock(&irq->irq_lock);
>> +
>> +	irq->hw = false;
>> +	irq->hwintid = 0;
>> +
>> +	spin_unlock(&irq->irq_lock);
>> +
>>  	return 0;
>>  }
>>  
>> @@ -520,3 +600,15 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
>>  
>>  	return pending;
>>  }
>> +
>> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, u32 intid)
>> +{
>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +	bool map_is_active;
>> +
>> +	spin_lock(&irq->irq_lock);
>> +	map_is_active = irq->hw && irq->active;
>> +	spin_unlock(&irq->irq_lock);
>> +
>> +	return map_is_active;
>> +}
>> -- 
>> 2.7.3
>>
>> --
>> 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] 276+ messages in thread

* Re: [RFC PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
  2016-04-01  8:20       ` Eric Auger
@ 2016-04-01  9:00         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-01  9:00 UTC (permalink / raw)
  To: Eric Auger; +Cc: Andre Przywara, Marc Zyngier, kvmarm, kvm, linux-arm-kernel

On Fri, Apr 01, 2016 at 10:20:59AM +0200, Eric Auger wrote:
> Hi Christoffer,
> On 03/31/2016 07:59 PM, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:05:03AM +0000, Andre Przywara wrote:
> >> From: Eric Auger <eric.auger@linaro.org>
> >>
> >> This patch allocates and initializes the data structures used
> >> to model the vgic distributor and virtual cpu interfaces. At that
> >> stage the number of IRQs and number of virtual CPUs is frozen.
> >>
> >> The following realy_init functions are kept since they are called from
> >> arm.c. However they may disappear in subsequent patches since
> >> they are void.
> >>
> >> vgic_[v2|v3]_enable still is stubbed at this stage.
> > 
> > early init ?
> Indeed I can mention those functions also are stubbed. Eventually it may
> make sense to remove their call from arm.c but this was not done yet in
> this series to avoid touching non vgic code.

oh, my comment was to the fact that you wrote realy_init above... :)

-Christoffer

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

* [RFC PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
@ 2016-04-01  9:00         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-01  9:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 01, 2016 at 10:20:59AM +0200, Eric Auger wrote:
> Hi Christoffer,
> On 03/31/2016 07:59 PM, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:05:03AM +0000, Andre Przywara wrote:
> >> From: Eric Auger <eric.auger@linaro.org>
> >>
> >> This patch allocates and initializes the data structures used
> >> to model the vgic distributor and virtual cpu interfaces. At that
> >> stage the number of IRQs and number of virtual CPUs is frozen.
> >>
> >> The following realy_init functions are kept since they are called from
> >> arm.c. However they may disappear in subsequent patches since
> >> they are void.
> >>
> >> vgic_[v2|v3]_enable still is stubbed at this stage.
> > 
> > early init ?
> Indeed I can mention those functions also are stubbed. Eventually it may
> make sense to remove their call from arm.c but this was not done yet in
> this series to avoid touching non vgic code.

oh, my comment was to the fact that you wrote realy_init above... :)

-Christoffer

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

* Re: [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-03-31  9:08     ` Christoffer Dall
@ 2016-04-01 12:11       ` André Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: André Przywara @ 2016-04-01 12:11 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, kvm, kvmarm, linux-arm-kernel

On 31/03/16 10:08, Christoffer Dall wrote:
> Hi Andre,
> 
> [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
> 
> On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
>> We register each register group of the distributor and redistributors
>> as separate regions of the kvm-io-bus framework. This way calls get
>> directly handed over to the actual handler.
>> This puts a lot more regions into kvm-io-bus than what we use at the
>> moment on other architectures, so we will probably need to revisit the
>> implementation of the framework later to be more efficient.
> 
> Looking more carefully at the KVM IO bus stuff, it looks like it is
> indeed designed to be a *per device* thing you register, not a *per
> register* thing.
> 
> My comments to Vladimir's bug report notwithstanding, there's still a
> choice here to:
> 
> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> 
> 2) Build a KVM architectureal generic framework on top of the IO bus
> framework to handle individual register regions.

> 
> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> and handle the individual register region business locally within the
> arm/vgic code.

I am for either 1) or 2). I consider "the old way" a kludge. We couldn't
use KVM IO bus when the VGIC was introduced, because it lacked the VCPU
parameter. Later this was fixed, but introducing the framework all the
way down to the individual register handlers wasn't feasible without
rewriting much of the VGIC. Since we now do exactly this, I'd love to
pimp the KVM IO bus framework to properly cope with the "many register"
use case. Instead of writing KVM/ARM specific code I'd rather see this
solved properly for the whole KVM subsystem. The other framework users
don't seem to have high demands, so adjusting them should be easy.
If this is considered too much for the first patch incarnation, we could
consider a temporary wrapper that gets removed later when the KVM IO bus
framework gets fixed/reworked - but we should keep the VGIC MMIO handler
prototypes in a way that allows them to be called directly later.

Cheers,
Andre.

>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> ---
>>  include/kvm/vgic/vgic.h       |   9 ++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
>>  3 files changed, 250 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 2ce9b4a..a8262c7 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -106,6 +106,12 @@ struct vgic_irq {
>>  	enum vgic_irq_config config;	/* Level or edge */
>>  };
>>  
>> +struct vgic_io_device {
>> +	gpa_t base_addr;
>> +	struct kvm_vcpu *redist_vcpu;
>> +	struct kvm_io_device dev;
>> +};
>> +
>>  struct vgic_dist {
>>  	bool			in_kernel;
>>  	bool			ready;
>> @@ -132,6 +138,9 @@ struct vgic_dist {
>>  	u32			enabled;
>>  
>>  	struct vgic_irq		*spis;
>> +
>> +	struct vgic_io_device	*dist_iodevs;
>> +	struct vgic_io_device	*redist_iodevs;
>>  };
>>  
>>  struct vgic_v2_cpu_if {
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> new file mode 100644
>> index 0000000..26c46e7
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -0,0 +1,194 @@
>> +/*
>> + * VGIC MMIO handling functions
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <kvm/iodev.h>
>> +#include <kvm/vgic/vgic.h>
>> +#include <linux/bitops.h>
>> +#include <linux/irqchip/arm-gic.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic_mmio.h"
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val)
>> +{
>> +	value = cpu_to_le32(value) >> (offset * 8);
>> +	memcpy(val, &value, len);
>> +}
>> +
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
>> +{
>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
>> +	return origvalue;
>> +}
>> +
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +void write_mask64(u64 value, int offset, int len, void *val)
>> +{
>> +	value = cpu_to_le64(value) >> (offset * 8);
>> +	memcpy(val, &value, len);
>> +}
>> +
>> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
> 
> I'm confuses in general.  Can you explain what these mask functions do
> overall at some higher level?
> 
> I also keep having a feeling that mixing endianness stuff into the
> emulation code itself is the wrong way to go about it.  The emulation
> code should just deal with register values of varying length and the
> interface to the VGIC should abstract all endianness nonsense for us,
> but I also think I've lost this argument some time in the past.  Sigh.
> 
> But, is the maximum read/write unit for any MMIO access not a 64-bit
> value?  So why can't we let the VGIC emulation code simply take/return a
> u64 which is then masked off/morphed into the right endianness outside
> the VGIC code?
> 
>> +u64 mask64(u64 origvalue, int offset, int len, const void *val)
>> +{
>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
>> +	return origvalue;
>> +}
>> +#endif
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, void *val)
>> +{
>> +	memset(val, 0, len);
>> +
>> +	return 0;
>> +}
>> +
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, const void *val)
>> +{
>> +	return 0;
>> +}
> 
> I dislike the use of 'this' as a parameter name, why not 'dev' ?
> 
>> +
>> +static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
>> +			      struct kvm_io_device *this,
>> +			      gpa_t addr, int len, void *val)
>> +{
>> +	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
>> +		vcpu->vcpu_id, (unsigned long long)addr);
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
>> +			       struct kvm_io_device *this,
>> +			       gpa_t addr, int len, const void *val)
>> +{
>> +	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
>> +		vcpu->vcpu_id, (unsigned long long)addr);
>> +	return 0;
>> +}
>> +
>> +struct vgic_register_region vgic_v2_dist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +};
>> +
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +				  struct vgic_register_region *reg_desc,
>> +				  struct vgic_io_device *region,
>> +				  int nr_irqs, bool offset_private)
>> +{
>> +	int bpi = reg_desc->bits_per_irq;
>> +	int offset = 0;
>> +	int len, ret;
>> +
>> +	region->base_addr	+= reg_desc->reg_offset;
>> +	region->redist_vcpu	= vcpu;
>> +
>> +	kvm_iodevice_init(&region->dev, &reg_desc->ops);
>> +
>> +	if (bpi) {
>> +		len = (bpi * nr_irqs) / 8;
>> +		if (offset_private)
>> +			offset = (bpi * VGIC_NR_PRIVATE_IRQS) / 8;
>> +	} else {
>> +		len = reg_desc->len;
>> +	}
>> +
>> +	mutex_lock(&kvm->slots_lock);
>> +	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +				      region->base_addr + offset,
>> +				      len - offset, &region->dev);
>> +	mutex_unlock(&kvm->slots_lock);
>> +
>> +	return ret;
>> +}
>> +
>> +int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>> +			       enum vgic_type type)
>> +{
>> +	struct vgic_io_device *regions;
>> +	struct vgic_register_region *reg_desc;
>> +	int nr_regions;
>> +	int nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +	int i;
>> +	int ret = 0;
>> +
>> +	switch (type) {
>> +	case VGIC_V2:
>> +		reg_desc = vgic_v2_dist_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>> +		break;
>> +	default:
>> +		BUG_ON(1);
>> +	}
>> +
>> +	regions = kmalloc_array(nr_regions, sizeof(struct vgic_io_device),
>> +				GFP_KERNEL);
>> +	if (!regions)
>> +		return -ENOMEM;
>> +
>> +	for (i = 0; i < nr_regions; i++) {
>> +		regions[i].base_addr	= dist_base_address;
>> +
>> +		ret = kvm_vgic_register_mmio_region(kvm, NULL, reg_desc,
>> +						    regions + i, nr_irqs,
>> +						    type == VGIC_V3);
>> +		if (ret)
>> +			break;
>> +
>> +		reg_desc++;
>> +	}
>> +
>> +	if (ret) {
>> +		mutex_lock(&kvm->slots_lock);
>> +		for (i--; i >= 0; i--)
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &regions[i].dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +	} else {
>> +		kvm->arch.vgic.dist_iodevs = regions;
>> +	}
>> +
>> +	return ret;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.h b/virt/kvm/arm/vgic/vgic_mmio.h
>> new file mode 100644
>> index 0000000..cf2314c
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.h
>> @@ -0,0 +1,47 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * 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_ARM_VGIC_MMIO_H__
>> +#define __KVM_ARM_VGIC_MMIO_H__
>> +
>> +struct vgic_register_region {
>> +	int reg_offset;
>> +	int len;
>> +	int bits_per_irq;
>> +	struct kvm_io_device_ops ops;
>> +};
>> +
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(name, read_ops, write_ops, bpi) \
>> +	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
>> +	 .ops.read = read_ops, .ops.write = write_ops}
>> +#define REGISTER_DESC_WITH_LENGTH(name, read_ops, write_ops, length) \
>> +	{.reg_offset = name, .bits_per_irq = 0, .len = length, \
>> +	 .ops.read = read_ops, .ops.write = write_ops}
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, void *val);
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, const void *val);
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +				  struct vgic_register_region *reg_desc,
>> +				  struct vgic_io_device *region,
>> +				  int nr_irqs, bool offset_private);
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val);
>> +void write_mask64(u64 value, int offset, int len, void *val);
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val);
>> +u64 mask64(u64 origvalue, int offset, int len, const void *val);
>> +
>> +#endif
>> -- 
>> 2.7.3
>>
>>
> 
> Thanks,
> -Christoffer
> 

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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-04-01 12:11       ` André Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: André Przywara @ 2016-04-01 12:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 31/03/16 10:08, Christoffer Dall wrote:
> Hi Andre,
> 
> [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
> 
> On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
>> We register each register group of the distributor and redistributors
>> as separate regions of the kvm-io-bus framework. This way calls get
>> directly handed over to the actual handler.
>> This puts a lot more regions into kvm-io-bus than what we use at the
>> moment on other architectures, so we will probably need to revisit the
>> implementation of the framework later to be more efficient.
> 
> Looking more carefully at the KVM IO bus stuff, it looks like it is
> indeed designed to be a *per device* thing you register, not a *per
> register* thing.
> 
> My comments to Vladimir's bug report notwithstanding, there's still a
> choice here to:
> 
> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> 
> 2) Build a KVM architectureal generic framework on top of the IO bus
> framework to handle individual register regions.

> 
> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> and handle the individual register region business locally within the
> arm/vgic code.

I am for either 1) or 2). I consider "the old way" a kludge. We couldn't
use KVM IO bus when the VGIC was introduced, because it lacked the VCPU
parameter. Later this was fixed, but introducing the framework all the
way down to the individual register handlers wasn't feasible without
rewriting much of the VGIC. Since we now do exactly this, I'd love to
pimp the KVM IO bus framework to properly cope with the "many register"
use case. Instead of writing KVM/ARM specific code I'd rather see this
solved properly for the whole KVM subsystem. The other framework users
don't seem to have high demands, so adjusting them should be easy.
If this is considered too much for the first patch incarnation, we could
consider a temporary wrapper that gets removed later when the KVM IO bus
framework gets fixed/reworked - but we should keep the VGIC MMIO handler
prototypes in a way that allows them to be called directly later.

Cheers,
Andre.

>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> ---
>>  include/kvm/vgic/vgic.h       |   9 ++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
>>  3 files changed, 250 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 2ce9b4a..a8262c7 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -106,6 +106,12 @@ struct vgic_irq {
>>  	enum vgic_irq_config config;	/* Level or edge */
>>  };
>>  
>> +struct vgic_io_device {
>> +	gpa_t base_addr;
>> +	struct kvm_vcpu *redist_vcpu;
>> +	struct kvm_io_device dev;
>> +};
>> +
>>  struct vgic_dist {
>>  	bool			in_kernel;
>>  	bool			ready;
>> @@ -132,6 +138,9 @@ struct vgic_dist {
>>  	u32			enabled;
>>  
>>  	struct vgic_irq		*spis;
>> +
>> +	struct vgic_io_device	*dist_iodevs;
>> +	struct vgic_io_device	*redist_iodevs;
>>  };
>>  
>>  struct vgic_v2_cpu_if {
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> new file mode 100644
>> index 0000000..26c46e7
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -0,0 +1,194 @@
>> +/*
>> + * VGIC MMIO handling functions
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <kvm/iodev.h>
>> +#include <kvm/vgic/vgic.h>
>> +#include <linux/bitops.h>
>> +#include <linux/irqchip/arm-gic.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic_mmio.h"
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val)
>> +{
>> +	value = cpu_to_le32(value) >> (offset * 8);
>> +	memcpy(val, &value, len);
>> +}
>> +
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
>> +{
>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
>> +	return origvalue;
>> +}
>> +
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +void write_mask64(u64 value, int offset, int len, void *val)
>> +{
>> +	value = cpu_to_le64(value) >> (offset * 8);
>> +	memcpy(val, &value, len);
>> +}
>> +
>> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
> 
> I'm confuses in general.  Can you explain what these mask functions do
> overall at some higher level?
> 
> I also keep having a feeling that mixing endianness stuff into the
> emulation code itself is the wrong way to go about it.  The emulation
> code should just deal with register values of varying length and the
> interface to the VGIC should abstract all endianness nonsense for us,
> but I also think I've lost this argument some time in the past.  Sigh.
> 
> But, is the maximum read/write unit for any MMIO access not a 64-bit
> value?  So why can't we let the VGIC emulation code simply take/return a
> u64 which is then masked off/morphed into the right endianness outside
> the VGIC code?
> 
>> +u64 mask64(u64 origvalue, int offset, int len, const void *val)
>> +{
>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
>> +	return origvalue;
>> +}
>> +#endif
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, void *val)
>> +{
>> +	memset(val, 0, len);
>> +
>> +	return 0;
>> +}
>> +
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, const void *val)
>> +{
>> +	return 0;
>> +}
> 
> I dislike the use of 'this' as a parameter name, why not 'dev' ?
> 
>> +
>> +static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
>> +			      struct kvm_io_device *this,
>> +			      gpa_t addr, int len, void *val)
>> +{
>> +	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
>> +		vcpu->vcpu_id, (unsigned long long)addr);
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
>> +			       struct kvm_io_device *this,
>> +			       gpa_t addr, int len, const void *val)
>> +{
>> +	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
>> +		vcpu->vcpu_id, (unsigned long long)addr);
>> +	return 0;
>> +}
>> +
>> +struct vgic_register_region vgic_v2_dist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +};
>> +
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +				  struct vgic_register_region *reg_desc,
>> +				  struct vgic_io_device *region,
>> +				  int nr_irqs, bool offset_private)
>> +{
>> +	int bpi = reg_desc->bits_per_irq;
>> +	int offset = 0;
>> +	int len, ret;
>> +
>> +	region->base_addr	+= reg_desc->reg_offset;
>> +	region->redist_vcpu	= vcpu;
>> +
>> +	kvm_iodevice_init(&region->dev, &reg_desc->ops);
>> +
>> +	if (bpi) {
>> +		len = (bpi * nr_irqs) / 8;
>> +		if (offset_private)
>> +			offset = (bpi * VGIC_NR_PRIVATE_IRQS) / 8;
>> +	} else {
>> +		len = reg_desc->len;
>> +	}
>> +
>> +	mutex_lock(&kvm->slots_lock);
>> +	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +				      region->base_addr + offset,
>> +				      len - offset, &region->dev);
>> +	mutex_unlock(&kvm->slots_lock);
>> +
>> +	return ret;
>> +}
>> +
>> +int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>> +			       enum vgic_type type)
>> +{
>> +	struct vgic_io_device *regions;
>> +	struct vgic_register_region *reg_desc;
>> +	int nr_regions;
>> +	int nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +	int i;
>> +	int ret = 0;
>> +
>> +	switch (type) {
>> +	case VGIC_V2:
>> +		reg_desc = vgic_v2_dist_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>> +		break;
>> +	default:
>> +		BUG_ON(1);
>> +	}
>> +
>> +	regions = kmalloc_array(nr_regions, sizeof(struct vgic_io_device),
>> +				GFP_KERNEL);
>> +	if (!regions)
>> +		return -ENOMEM;
>> +
>> +	for (i = 0; i < nr_regions; i++) {
>> +		regions[i].base_addr	= dist_base_address;
>> +
>> +		ret = kvm_vgic_register_mmio_region(kvm, NULL, reg_desc,
>> +						    regions + i, nr_irqs,
>> +						    type == VGIC_V3);
>> +		if (ret)
>> +			break;
>> +
>> +		reg_desc++;
>> +	}
>> +
>> +	if (ret) {
>> +		mutex_lock(&kvm->slots_lock);
>> +		for (i--; i >= 0; i--)
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &regions[i].dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +	} else {
>> +		kvm->arch.vgic.dist_iodevs = regions;
>> +	}
>> +
>> +	return ret;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.h b/virt/kvm/arm/vgic/vgic_mmio.h
>> new file mode 100644
>> index 0000000..cf2314c
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.h
>> @@ -0,0 +1,47 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * 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_ARM_VGIC_MMIO_H__
>> +#define __KVM_ARM_VGIC_MMIO_H__
>> +
>> +struct vgic_register_region {
>> +	int reg_offset;
>> +	int len;
>> +	int bits_per_irq;
>> +	struct kvm_io_device_ops ops;
>> +};
>> +
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(name, read_ops, write_ops, bpi) \
>> +	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
>> +	 .ops.read = read_ops, .ops.write = write_ops}
>> +#define REGISTER_DESC_WITH_LENGTH(name, read_ops, write_ops, length) \
>> +	{.reg_offset = name, .bits_per_irq = 0, .len = length, \
>> +	 .ops.read = read_ops, .ops.write = write_ops}
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, void *val);
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, const void *val);
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +				  struct vgic_register_region *reg_desc,
>> +				  struct vgic_io_device *region,
>> +				  int nr_irqs, bool offset_private);
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val);
>> +void write_mask64(u64 value, int offset, int len, void *val);
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val);
>> +u64 mask64(u64 origvalue, int offset, int len, const void *val);
>> +
>> +#endif
>> -- 
>> 2.7.3
>>
>>
> 
> Thanks,
> -Christoffer
> 

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

* Re: [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-04-01 12:11       ` André Przywara
@ 2016-04-01 12:17         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-01 12:17 UTC (permalink / raw)
  To: André Przywara
  Cc: Marc Zyngier, Eric Auger, linux-arm-kernel, kvmarm, kvm

On Fri, Apr 01, 2016 at 01:11:06PM +0100, André Przywara wrote:
> On 31/03/16 10:08, Christoffer Dall wrote:
> > Hi Andre,
> > 
> > [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
> > 
> > On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
> >> We register each register group of the distributor and redistributors
> >> as separate regions of the kvm-io-bus framework. This way calls get
> >> directly handed over to the actual handler.
> >> This puts a lot more regions into kvm-io-bus than what we use at the
> >> moment on other architectures, so we will probably need to revisit the
> >> implementation of the framework later to be more efficient.
> > 
> > Looking more carefully at the KVM IO bus stuff, it looks like it is
> > indeed designed to be a *per device* thing you register, not a *per
> > register* thing.
> > 
> > My comments to Vladimir's bug report notwithstanding, there's still a
> > choice here to:
> > 
> > 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> > 
> > 2) Build a KVM architectureal generic framework on top of the IO bus
> > framework to handle individual register regions.
> 
> > 
> > 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> > and handle the individual register region business locally within the
> > arm/vgic code.
> 
> I am for either 1) or 2). I consider "the old way" a kludge. We couldn't
> use KVM IO bus when the VGIC was introduced, because it lacked the VCPU
> parameter. Later this was fixed, but introducing the framework all the
> way down to the individual register handlers wasn't feasible without
> rewriting much of the VGIC. Since we now do exactly this, I'd love to
> pimp the KVM IO bus framework to properly cope with the "many register"
> use case. Instead of writing KVM/ARM specific code I'd rather see this
> solved properly for the whole KVM subsystem. The other framework users
> don't seem to have high demands, so adjusting them should be easy.
> If this is considered too much for the first patch incarnation, we could
> consider a temporary wrapper that gets removed later when the KVM IO bus
> framework gets fixed/reworked - but we should keep the VGIC MMIO handler
> prototypes in a way that allows them to be called directly later.
> 
I was somewhere between (2) and (3), but given Paolo leans towards (3),
and that we have plenty of work here already, I think that doing (3) in
a way that allows us to do (2) easily later on if we feel like it is
probably the rigth direction to take at the moment.

Thanks,
-Christoffer

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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-04-01 12:17         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-01 12:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 01, 2016 at 01:11:06PM +0100, Andr? Przywara wrote:
> On 31/03/16 10:08, Christoffer Dall wrote:
> > Hi Andre,
> > 
> > [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
> > 
> > On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
> >> We register each register group of the distributor and redistributors
> >> as separate regions of the kvm-io-bus framework. This way calls get
> >> directly handed over to the actual handler.
> >> This puts a lot more regions into kvm-io-bus than what we use at the
> >> moment on other architectures, so we will probably need to revisit the
> >> implementation of the framework later to be more efficient.
> > 
> > Looking more carefully at the KVM IO bus stuff, it looks like it is
> > indeed designed to be a *per device* thing you register, not a *per
> > register* thing.
> > 
> > My comments to Vladimir's bug report notwithstanding, there's still a
> > choice here to:
> > 
> > 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> > 
> > 2) Build a KVM architectureal generic framework on top of the IO bus
> > framework to handle individual register regions.
> 
> > 
> > 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> > and handle the individual register region business locally within the
> > arm/vgic code.
> 
> I am for either 1) or 2). I consider "the old way" a kludge. We couldn't
> use KVM IO bus when the VGIC was introduced, because it lacked the VCPU
> parameter. Later this was fixed, but introducing the framework all the
> way down to the individual register handlers wasn't feasible without
> rewriting much of the VGIC. Since we now do exactly this, I'd love to
> pimp the KVM IO bus framework to properly cope with the "many register"
> use case. Instead of writing KVM/ARM specific code I'd rather see this
> solved properly for the whole KVM subsystem. The other framework users
> don't seem to have high demands, so adjusting them should be easy.
> If this is considered too much for the first patch incarnation, we could
> consider a temporary wrapper that gets removed later when the KVM IO bus
> framework gets fixed/reworked - but we should keep the VGIC MMIO handler
> prototypes in a way that allows them to be called directly later.
> 
I was somewhere between (2) and (3), but given Paolo leans towards (3),
and that we have plenty of work here already, I think that doing (3) in
a way that allows us to do (2) easily later on if we feel like it is
probably the rigth direction to take at the moment.

Thanks,
-Christoffer

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

* Re: [RFC PATCH 01/45] KVM: arm/arm64: add missing MMIO data write-back
  2016-03-29 12:33     ` Christoffer Dall
@ 2016-04-05 12:12       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-05 12:12 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Eric Auger, kvm, Marc Zyngier, kvmarm, linux-arm-kernel

On 29/03/16 13:33, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:24AM +0000, Andre Przywara wrote:
>> When the kernel was handling a guest MMIO access internally, we need
>> to copy the emulation result into the run->mmio structure in order
>> for the kvm_handle_mmio_return() function to pick it up and inject
>> the result back into the guest.
>> Currently the only user of kvm_io_bus for ARM is the VGIC, which did
>> this copying itself, so this was not causing issues so far.
>> But with upcoming kvm_io_bus users we need to do the copying here.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  arch/arm/kvm/mmio.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
>> index 0f6600f..d5c2727 100644
>> --- a/arch/arm/kvm/mmio.c
>> +++ b/arch/arm/kvm/mmio.c
>> @@ -206,7 +206,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>>  	run->mmio.is_write	= is_write;
>>  	run->mmio.phys_addr	= fault_ipa;
>>  	run->mmio.len		= len;
>> -	if (is_write)
>> +	if (is_write || !ret)
>>  		memcpy(run->mmio.data, data_buf, len);
> 
> I had a really hard time understanding this, how about this instead:

Admittedly this is the shortest possible fix. I also had a rework closer
to your version, which also avoided copying the arguments in some cases,
but I thought a smaller diff would be more suitable, since this is
actually a fix.

Shall I add a comment here or post my version of the fix instead?

Cheers,
Andre.

> diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
> index 0f6600f..0158e9e 100644
> --- a/arch/arm/kvm/mmio.c
> +++ b/arch/arm/kvm/mmio.c
> @@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
>  
>  /**
>   * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
> + *			     or in-kernel IO emulation
> + *
>   * @vcpu: The VCPU pointer
>   * @run:  The VCPU run struct containing the mmio data
> - *
> - * This should only be called after returning from userspace for MMIO load
> - * emulation.
>   */
>  int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  {
> @@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>  	run->mmio.is_write	= is_write;
>  	run->mmio.phys_addr	= fault_ipa;
>  	run->mmio.len		= len;
> -	if (is_write)
> -		memcpy(run->mmio.data, data_buf, len);
>  
>  	if (!ret) {
>  		/* We handled the access successfully in the kernel. */
> +		if (!is_write)
> +			memcpy(run->mmio.data, data_buf, len);
>  		vcpu->stat.mmio_exit_kernel++;
>  		kvm_handle_mmio_return(vcpu, run);
>  		return 1;
> -	} else {
> -		vcpu->stat.mmio_exit_user++;
>  	}
>  
> +	if (is_write)
> +		memcpy(run->mmio.data, data_buf, len);
> +	vcpu->stat.mmio_exit_user++;
>  	run->exit_reason	= KVM_EXIT_MMIO;
>  	return 0;
>  }
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index 00429b3..63e99cb 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -850,12 +850,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
>  		updated_state = false;
>  	}
>  	spin_unlock(&dist->lock);
> -	run->mmio.is_write	= is_write;
> -	run->mmio.len		= len;
> -	run->mmio.phys_addr	= addr;
> -	memcpy(run->mmio.data, val, len);
> -
> -	kvm_handle_mmio_return(vcpu, run);
>  
>  	if (updated_state)
>  		vgic_kick_vcpus(vcpu->kvm);
> 

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

* [RFC PATCH 01/45] KVM: arm/arm64: add missing MMIO data write-back
@ 2016-04-05 12:12       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-05 12:12 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/03/16 13:33, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:24AM +0000, Andre Przywara wrote:
>> When the kernel was handling a guest MMIO access internally, we need
>> to copy the emulation result into the run->mmio structure in order
>> for the kvm_handle_mmio_return() function to pick it up and inject
>> the result back into the guest.
>> Currently the only user of kvm_io_bus for ARM is the VGIC, which did
>> this copying itself, so this was not causing issues so far.
>> But with upcoming kvm_io_bus users we need to do the copying here.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  arch/arm/kvm/mmio.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
>> index 0f6600f..d5c2727 100644
>> --- a/arch/arm/kvm/mmio.c
>> +++ b/arch/arm/kvm/mmio.c
>> @@ -206,7 +206,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>>  	run->mmio.is_write	= is_write;
>>  	run->mmio.phys_addr	= fault_ipa;
>>  	run->mmio.len		= len;
>> -	if (is_write)
>> +	if (is_write || !ret)
>>  		memcpy(run->mmio.data, data_buf, len);
> 
> I had a really hard time understanding this, how about this instead:

Admittedly this is the shortest possible fix. I also had a rework closer
to your version, which also avoided copying the arguments in some cases,
but I thought a smaller diff would be more suitable, since this is
actually a fix.

Shall I add a comment here or post my version of the fix instead?

Cheers,
Andre.

> diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
> index 0f6600f..0158e9e 100644
> --- a/arch/arm/kvm/mmio.c
> +++ b/arch/arm/kvm/mmio.c
> @@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
>  
>  /**
>   * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
> + *			     or in-kernel IO emulation
> + *
>   * @vcpu: The VCPU pointer
>   * @run:  The VCPU run struct containing the mmio data
> - *
> - * This should only be called after returning from userspace for MMIO load
> - * emulation.
>   */
>  int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  {
> @@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>  	run->mmio.is_write	= is_write;
>  	run->mmio.phys_addr	= fault_ipa;
>  	run->mmio.len		= len;
> -	if (is_write)
> -		memcpy(run->mmio.data, data_buf, len);
>  
>  	if (!ret) {
>  		/* We handled the access successfully in the kernel. */
> +		if (!is_write)
> +			memcpy(run->mmio.data, data_buf, len);
>  		vcpu->stat.mmio_exit_kernel++;
>  		kvm_handle_mmio_return(vcpu, run);
>  		return 1;
> -	} else {
> -		vcpu->stat.mmio_exit_user++;
>  	}
>  
> +	if (is_write)
> +		memcpy(run->mmio.data, data_buf, len);
> +	vcpu->stat.mmio_exit_user++;
>  	run->exit_reason	= KVM_EXIT_MMIO;
>  	return 0;
>  }
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index 00429b3..63e99cb 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -850,12 +850,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
>  		updated_state = false;
>  	}
>  	spin_unlock(&dist->lock);
> -	run->mmio.is_write	= is_write;
> -	run->mmio.len		= len;
> -	run->mmio.phys_addr	= addr;
> -	memcpy(run->mmio.data, val, len);
> -
> -	kvm_handle_mmio_return(vcpu, run);
>  
>  	if (updated_state)
>  		vgic_kick_vcpus(vcpu->kvm);
> 

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

* Re: [RFC PATCH 01/45] KVM: arm/arm64: add missing MMIO data write-back
  2016-04-05 12:12       ` Andre Przywara
@ 2016-04-05 12:58         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-05 12:58 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel, Eric Auger

On Tue, Apr 05, 2016 at 01:12:04PM +0100, Andre Przywara wrote:
> On 29/03/16 13:33, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:24AM +0000, Andre Przywara wrote:
> >> When the kernel was handling a guest MMIO access internally, we need
> >> to copy the emulation result into the run->mmio structure in order
> >> for the kvm_handle_mmio_return() function to pick it up and inject
> >> the result back into the guest.
> >> Currently the only user of kvm_io_bus for ARM is the VGIC, which did
> >> this copying itself, so this was not causing issues so far.
> >> But with upcoming kvm_io_bus users we need to do the copying here.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  arch/arm/kvm/mmio.c | 2 +-
> >>  1 file changed, 1 insertion(+), 1 deletion(-)
> >>
> >> diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
> >> index 0f6600f..d5c2727 100644
> >> --- a/arch/arm/kvm/mmio.c
> >> +++ b/arch/arm/kvm/mmio.c
> >> @@ -206,7 +206,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
> >>  	run->mmio.is_write	= is_write;
> >>  	run->mmio.phys_addr	= fault_ipa;
> >>  	run->mmio.len		= len;
> >> -	if (is_write)
> >> +	if (is_write || !ret)
> >>  		memcpy(run->mmio.data, data_buf, len);
> > 
> > I had a really hard time understanding this, how about this instead:
> 
> Admittedly this is the shortest possible fix. I also had a rework closer
> to your version, which also avoided copying the arguments in some cases,
> but I thought a smaller diff would be more suitable, since this is
> actually a fix.
> 
> Shall I add a comment here or post my version of the fix instead?
> 
Let me test what I have below more thoroughly and send that as a patch.

-Christoffer

> 
> > diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
> > index 0f6600f..0158e9e 100644
> > --- a/arch/arm/kvm/mmio.c
> > +++ b/arch/arm/kvm/mmio.c
> > @@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
> >  
> >  /**
> >   * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
> > + *			     or in-kernel IO emulation
> > + *
> >   * @vcpu: The VCPU pointer
> >   * @run:  The VCPU run struct containing the mmio data
> > - *
> > - * This should only be called after returning from userspace for MMIO load
> > - * emulation.
> >   */
> >  int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  {
> > @@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
> >  	run->mmio.is_write	= is_write;
> >  	run->mmio.phys_addr	= fault_ipa;
> >  	run->mmio.len		= len;
> > -	if (is_write)
> > -		memcpy(run->mmio.data, data_buf, len);
> >  
> >  	if (!ret) {
> >  		/* We handled the access successfully in the kernel. */
> > +		if (!is_write)
> > +			memcpy(run->mmio.data, data_buf, len);
> >  		vcpu->stat.mmio_exit_kernel++;
> >  		kvm_handle_mmio_return(vcpu, run);
> >  		return 1;
> > -	} else {
> > -		vcpu->stat.mmio_exit_user++;
> >  	}
> >  
> > +	if (is_write)
> > +		memcpy(run->mmio.data, data_buf, len);
> > +	vcpu->stat.mmio_exit_user++;
> >  	run->exit_reason	= KVM_EXIT_MMIO;
> >  	return 0;
> >  }
> > diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> > index 00429b3..63e99cb 100644
> > --- a/virt/kvm/arm/vgic.c
> > +++ b/virt/kvm/arm/vgic.c
> > @@ -850,12 +850,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
> >  		updated_state = false;
> >  	}
> >  	spin_unlock(&dist->lock);
> > -	run->mmio.is_write	= is_write;
> > -	run->mmio.len		= len;
> > -	run->mmio.phys_addr	= addr;
> > -	memcpy(run->mmio.data, val, len);
> > -
> > -	kvm_handle_mmio_return(vcpu, run);
> >  
> >  	if (updated_state)
> >  		vgic_kick_vcpus(vcpu->kvm);
> > 
> 

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

* [RFC PATCH 01/45] KVM: arm/arm64: add missing MMIO data write-back
@ 2016-04-05 12:58         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-05 12:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 05, 2016 at 01:12:04PM +0100, Andre Przywara wrote:
> On 29/03/16 13:33, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:24AM +0000, Andre Przywara wrote:
> >> When the kernel was handling a guest MMIO access internally, we need
> >> to copy the emulation result into the run->mmio structure in order
> >> for the kvm_handle_mmio_return() function to pick it up and inject
> >> the result back into the guest.
> >> Currently the only user of kvm_io_bus for ARM is the VGIC, which did
> >> this copying itself, so this was not causing issues so far.
> >> But with upcoming kvm_io_bus users we need to do the copying here.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  arch/arm/kvm/mmio.c | 2 +-
> >>  1 file changed, 1 insertion(+), 1 deletion(-)
> >>
> >> diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
> >> index 0f6600f..d5c2727 100644
> >> --- a/arch/arm/kvm/mmio.c
> >> +++ b/arch/arm/kvm/mmio.c
> >> @@ -206,7 +206,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
> >>  	run->mmio.is_write	= is_write;
> >>  	run->mmio.phys_addr	= fault_ipa;
> >>  	run->mmio.len		= len;
> >> -	if (is_write)
> >> +	if (is_write || !ret)
> >>  		memcpy(run->mmio.data, data_buf, len);
> > 
> > I had a really hard time understanding this, how about this instead:
> 
> Admittedly this is the shortest possible fix. I also had a rework closer
> to your version, which also avoided copying the arguments in some cases,
> but I thought a smaller diff would be more suitable, since this is
> actually a fix.
> 
> Shall I add a comment here or post my version of the fix instead?
> 
Let me test what I have below more thoroughly and send that as a patch.

-Christoffer

> 
> > diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
> > index 0f6600f..0158e9e 100644
> > --- a/arch/arm/kvm/mmio.c
> > +++ b/arch/arm/kvm/mmio.c
> > @@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
> >  
> >  /**
> >   * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
> > + *			     or in-kernel IO emulation
> > + *
> >   * @vcpu: The VCPU pointer
> >   * @run:  The VCPU run struct containing the mmio data
> > - *
> > - * This should only be called after returning from userspace for MMIO load
> > - * emulation.
> >   */
> >  int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  {
> > @@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
> >  	run->mmio.is_write	= is_write;
> >  	run->mmio.phys_addr	= fault_ipa;
> >  	run->mmio.len		= len;
> > -	if (is_write)
> > -		memcpy(run->mmio.data, data_buf, len);
> >  
> >  	if (!ret) {
> >  		/* We handled the access successfully in the kernel. */
> > +		if (!is_write)
> > +			memcpy(run->mmio.data, data_buf, len);
> >  		vcpu->stat.mmio_exit_kernel++;
> >  		kvm_handle_mmio_return(vcpu, run);
> >  		return 1;
> > -	} else {
> > -		vcpu->stat.mmio_exit_user++;
> >  	}
> >  
> > +	if (is_write)
> > +		memcpy(run->mmio.data, data_buf, len);
> > +	vcpu->stat.mmio_exit_user++;
> >  	run->exit_reason	= KVM_EXIT_MMIO;
> >  	return 0;
> >  }
> > diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> > index 00429b3..63e99cb 100644
> > --- a/virt/kvm/arm/vgic.c
> > +++ b/virt/kvm/arm/vgic.c
> > @@ -850,12 +850,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
> >  		updated_state = false;
> >  	}
> >  	spin_unlock(&dist->lock);
> > -	run->mmio.is_write	= is_write;
> > -	run->mmio.len		= len;
> > -	run->mmio.phys_addr	= addr;
> > -	memcpy(run->mmio.data, val, len);
> > -
> > -	kvm_handle_mmio_return(vcpu, run);
> >  
> >  	if (updated_state)
> >  		vgic_kick_vcpus(vcpu->kvm);
> > 
> 

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

* Re: [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-03-29 13:09     ` Christoffer Dall
@ 2016-04-05 13:34       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-05 13:34 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 29/03/16 14:09, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>
>> Add a new header file for the new and improved GIC implementation.
>> The big change is that we now have a struct vgic_irq per IRQ instead
>> of spreading all the information over various bitmaps.
>>
>> We include this new header conditionally from within the old header
>> file for the time being to avoid touching all the users.
>>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/arm_vgic.h  |   5 ++
>>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 203 insertions(+)
>>  create mode 100644 include/kvm/vgic/vgic.h
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 7656a46..db289a2 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -19,6 +19,10 @@
>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>  #define __ASM_ARM_KVM_VGIC_H
>>  
>> +#ifdef CONFIG_KVM_NEW_VGIC
>> +#include <kvm/vgic/vgic.h>
>> +#else
>> +
>>  #include <linux/kernel.h>
>>  #include <linux/kvm.h>
>>  #include <linux/irqreturn.h>
>> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>  }
>>  #endif
>>  
>> +#endif	/* old VGIC include */
>>  #endif
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> new file mode 100644
>> index 0000000..659f8b1
>> --- /dev/null
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -0,0 +1,198 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/kvm.h>
>> +#include <linux/irqreturn.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/types.h>
>> +#include <kvm/iodev.h>
>> +
>> +#define VGIC_V3_MAX_CPUS	255
>> +#define VGIC_V2_MAX_CPUS	8
>> +#define VGIC_NR_IRQS_LEGACY     256
>> +#define VGIC_NR_SGIS		16
>> +#define VGIC_NR_PPIS		16
>> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
>> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
>> +#define VGIC_MAX_SPI		1019
>> +#define VGIC_MAX_RESERVED	1023
>> +#define VGIC_MIN_LPI		8192
>> +
>> +enum vgic_type {
>> +	VGIC_V2,		/* Good ol' GICv2 */
>> +	VGIC_V3,		/* New fancy GICv3 */
>> +};
>> +
>> +/* same for all guests, as depending only on the _host's_ GIC model */
>> +struct vgic_global {
>> +	/* type of the host GIC */
>> +	enum vgic_type		type;
>> +
>> +	/* Physical address of vgic virtual cpu interface */
>> +	phys_addr_t		vcpu_base;
>> +
>> +	/* virtual control interface mapping */
>> +	void __iomem		*vctrl_base;
>> +
>> +	/* Number of implemented list registers */
>> +	int			nr_lr;
>> +
>> +	/* Maintenance IRQ number */
>> +	unsigned int		maint_irq;
>> +
>> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
>> +	int			max_gic_vcpus;
>> +
>> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
>> +	bool			can_emulate_gicv2;
>> +};
>> +
>> +extern struct vgic_global kvm_vgic_global_state;
>> +
>> +#define VGIC_V2_MAX_LRS		(1 << 6)
>> +#define VGIC_V3_MAX_LRS		16
>> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
>> +
>> +enum vgic_irq_config {
>> +	VGIC_CONFIG_EDGE = 0,
>> +	VGIC_CONFIG_LEVEL
>> +};
>> +
>> +struct vgic_irq {
>> +	spinlock_t irq_lock;		/* Protects the content of the struct */
>> +	struct list_head ap_list;
>> +
>> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
>> +					 * SPIs and LPIs: The VCPU whose ap_list
>> +					 * on which this is queued.
>> +					 */
>> +
>> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
>> +					 * be send to, as a result of the
>> +					 * targets reg (v2) or the
>> +					 * affinity reg (v3).
>> +					 */
>> +
>> +	u32 intid;			/* Guest visible INTID */
>> +	bool pending;
>> +	bool line_level;		/* Level only */
>> +	bool soft_pending;		/* Level only */
>> +	bool active;			/* not used for LPIs */
>> +	bool enabled;
>> +	bool hw;			/* Tied to HW IRQ */
>> +	u32 hwintid;			/* HW INTID number */
>> +	union {
>> +		u8 targets;			/* GICv2 target VCPUs mask */
>> +		u32 mpidr;			/* GICv3 target VCPU */
>> +	};
>> +	u8 source;			/* GICv2 SGIs only */
>> +	u8 priority;
>> +	enum vgic_irq_config config;	/* Level or edge */
>> +};
>> +
>> +struct vgic_dist {
>> +	bool			in_kernel;
>> +	bool			ready;
>> +
>> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>> +	u32			vgic_model;
>> +
>> +	int			nr_spis;
>> +
>> +	/* TODO: Consider moving to global state */
>> +	/* Virtual control interface mapping */
>> +	void __iomem		*vctrl_base;
>> +
>> +	/* base addresses in guest physical address space: */
>> +	gpa_t			vgic_dist_base;		/* distributor */
>> +	union {
>> +		/* either a GICv2 CPU interface */
>> +		gpa_t			vgic_cpu_base;
>> +		/* or a number of GICv3 redistributor regions */
>> +		gpa_t			vgic_redist_base;
>> +	};
>> +
>> +	/* distributor enabled */
>> +	u32			enabled;
>> +
>> +	struct vgic_irq		*spis;
>> +};
>> +
>> +struct vgic_v2_cpu_if {
>> +	u32		vgic_hcr;
>> +	u32		vgic_vmcr;
>> +	u32		vgic_misr;	/* Saved only */
>> +	u64		vgic_eisr;	/* Saved only */
>> +	u64		vgic_elrsr;	/* Saved only */
>> +	u32		vgic_apr;
>> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
>> +};
>> +
>> +struct vgic_v3_cpu_if {
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +	u32		vgic_hcr;
>> +	u32		vgic_vmcr;
>> +	u32		vgic_sre;	/* Restored only, change ignored */
>> +	u32		vgic_misr;	/* Saved only */
>> +	u32		vgic_eisr;	/* Saved only */
>> +	u32		vgic_elrsr;	/* Saved only */
>> +	u32		vgic_ap0r[4];
>> +	u32		vgic_ap1r[4];
>> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
>> +#endif
>> +};
>> +
>> +struct vgic_cpu {
>> +	/* CPU vif control registers for world switch */
>> +	union {
>> +		struct vgic_v2_cpu_if	vgic_v2;
>> +		struct vgic_v3_cpu_if	vgic_v3;
>> +	};
>> +
>> +	/* TODO: Move nr_lr to a global state */
> 
> what is our current plan and status about this TODO?

The point is that the current HYP code is accessing this field. We do
have this field in the current "global" struct vgic_params there as
well, but this struct is (more or less) private to vgic-v2.c, so not
easily accessible from virt/kvm/arm/hyp/*.c.
So I suggest we keep this in here for the time being and eventually
remove it (and rework the save/restore code) once we get rid of the old
VGIC code.

Cheers,
Andre.

>> +	/* Number of list registers on this CPU */
>> +	int		nr_lr;
>> +
>> +	unsigned int used_lrs;
>> +	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
>> +
>> +	spinlock_t ap_list_lock;	/* Protects the ap_list */
>> +
>> +	/* list of IRQs for this VCPU to consider */
> 
> /*
>  * List of IRQs that this VCPU should consider because they are either
>  * Active or Pending (hence the name; AP list), or because they recently
>  * were one of the two and need to be migrated off this list to another
>  * VCPU.
>  */
> 
>> +	struct list_head ap_list_head;
>> +};
>> +
>> +#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>> +#define vgic_initialized(k)	(false)
>> +#define vgic_ready(k)		((k)->arch.vgic.ready)
>> +#define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>> +			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>> +
>> +/**
>> + * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>> + *
>> + * The host's GIC naturally limits the maximum amount of VCPUs a guest
>> + * can use.
>> + */
>> +static inline int kvm_vgic_get_max_vcpus(void)
>> +{
>> +	return kvm_vgic_global_state.max_gic_vcpus;
>> +}
>> +
>> +#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
>> -- 
>> 2.7.3
>>
> 
> Thanks,
> -Christoffer
> 

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

* [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-04-05 13:34       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-05 13:34 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 29/03/16 14:09, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>
>> Add a new header file for the new and improved GIC implementation.
>> The big change is that we now have a struct vgic_irq per IRQ instead
>> of spreading all the information over various bitmaps.
>>
>> We include this new header conditionally from within the old header
>> file for the time being to avoid touching all the users.
>>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/arm_vgic.h  |   5 ++
>>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 203 insertions(+)
>>  create mode 100644 include/kvm/vgic/vgic.h
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 7656a46..db289a2 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -19,6 +19,10 @@
>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>  #define __ASM_ARM_KVM_VGIC_H
>>  
>> +#ifdef CONFIG_KVM_NEW_VGIC
>> +#include <kvm/vgic/vgic.h>
>> +#else
>> +
>>  #include <linux/kernel.h>
>>  #include <linux/kvm.h>
>>  #include <linux/irqreturn.h>
>> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>  }
>>  #endif
>>  
>> +#endif	/* old VGIC include */
>>  #endif
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> new file mode 100644
>> index 0000000..659f8b1
>> --- /dev/null
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -0,0 +1,198 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/kvm.h>
>> +#include <linux/irqreturn.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/types.h>
>> +#include <kvm/iodev.h>
>> +
>> +#define VGIC_V3_MAX_CPUS	255
>> +#define VGIC_V2_MAX_CPUS	8
>> +#define VGIC_NR_IRQS_LEGACY     256
>> +#define VGIC_NR_SGIS		16
>> +#define VGIC_NR_PPIS		16
>> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
>> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
>> +#define VGIC_MAX_SPI		1019
>> +#define VGIC_MAX_RESERVED	1023
>> +#define VGIC_MIN_LPI		8192
>> +
>> +enum vgic_type {
>> +	VGIC_V2,		/* Good ol' GICv2 */
>> +	VGIC_V3,		/* New fancy GICv3 */
>> +};
>> +
>> +/* same for all guests, as depending only on the _host's_ GIC model */
>> +struct vgic_global {
>> +	/* type of the host GIC */
>> +	enum vgic_type		type;
>> +
>> +	/* Physical address of vgic virtual cpu interface */
>> +	phys_addr_t		vcpu_base;
>> +
>> +	/* virtual control interface mapping */
>> +	void __iomem		*vctrl_base;
>> +
>> +	/* Number of implemented list registers */
>> +	int			nr_lr;
>> +
>> +	/* Maintenance IRQ number */
>> +	unsigned int		maint_irq;
>> +
>> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
>> +	int			max_gic_vcpus;
>> +
>> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
>> +	bool			can_emulate_gicv2;
>> +};
>> +
>> +extern struct vgic_global kvm_vgic_global_state;
>> +
>> +#define VGIC_V2_MAX_LRS		(1 << 6)
>> +#define VGIC_V3_MAX_LRS		16
>> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
>> +
>> +enum vgic_irq_config {
>> +	VGIC_CONFIG_EDGE = 0,
>> +	VGIC_CONFIG_LEVEL
>> +};
>> +
>> +struct vgic_irq {
>> +	spinlock_t irq_lock;		/* Protects the content of the struct */
>> +	struct list_head ap_list;
>> +
>> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
>> +					 * SPIs and LPIs: The VCPU whose ap_list
>> +					 * on which this is queued.
>> +					 */
>> +
>> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
>> +					 * be send to, as a result of the
>> +					 * targets reg (v2) or the
>> +					 * affinity reg (v3).
>> +					 */
>> +
>> +	u32 intid;			/* Guest visible INTID */
>> +	bool pending;
>> +	bool line_level;		/* Level only */
>> +	bool soft_pending;		/* Level only */
>> +	bool active;			/* not used for LPIs */
>> +	bool enabled;
>> +	bool hw;			/* Tied to HW IRQ */
>> +	u32 hwintid;			/* HW INTID number */
>> +	union {
>> +		u8 targets;			/* GICv2 target VCPUs mask */
>> +		u32 mpidr;			/* GICv3 target VCPU */
>> +	};
>> +	u8 source;			/* GICv2 SGIs only */
>> +	u8 priority;
>> +	enum vgic_irq_config config;	/* Level or edge */
>> +};
>> +
>> +struct vgic_dist {
>> +	bool			in_kernel;
>> +	bool			ready;
>> +
>> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>> +	u32			vgic_model;
>> +
>> +	int			nr_spis;
>> +
>> +	/* TODO: Consider moving to global state */
>> +	/* Virtual control interface mapping */
>> +	void __iomem		*vctrl_base;
>> +
>> +	/* base addresses in guest physical address space: */
>> +	gpa_t			vgic_dist_base;		/* distributor */
>> +	union {
>> +		/* either a GICv2 CPU interface */
>> +		gpa_t			vgic_cpu_base;
>> +		/* or a number of GICv3 redistributor regions */
>> +		gpa_t			vgic_redist_base;
>> +	};
>> +
>> +	/* distributor enabled */
>> +	u32			enabled;
>> +
>> +	struct vgic_irq		*spis;
>> +};
>> +
>> +struct vgic_v2_cpu_if {
>> +	u32		vgic_hcr;
>> +	u32		vgic_vmcr;
>> +	u32		vgic_misr;	/* Saved only */
>> +	u64		vgic_eisr;	/* Saved only */
>> +	u64		vgic_elrsr;	/* Saved only */
>> +	u32		vgic_apr;
>> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
>> +};
>> +
>> +struct vgic_v3_cpu_if {
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +	u32		vgic_hcr;
>> +	u32		vgic_vmcr;
>> +	u32		vgic_sre;	/* Restored only, change ignored */
>> +	u32		vgic_misr;	/* Saved only */
>> +	u32		vgic_eisr;	/* Saved only */
>> +	u32		vgic_elrsr;	/* Saved only */
>> +	u32		vgic_ap0r[4];
>> +	u32		vgic_ap1r[4];
>> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
>> +#endif
>> +};
>> +
>> +struct vgic_cpu {
>> +	/* CPU vif control registers for world switch */
>> +	union {
>> +		struct vgic_v2_cpu_if	vgic_v2;
>> +		struct vgic_v3_cpu_if	vgic_v3;
>> +	};
>> +
>> +	/* TODO: Move nr_lr to a global state */
> 
> what is our current plan and status about this TODO?

The point is that the current HYP code is accessing this field. We do
have this field in the current "global" struct vgic_params there as
well, but this struct is (more or less) private to vgic-v2.c, so not
easily accessible from virt/kvm/arm/hyp/*.c.
So I suggest we keep this in here for the time being and eventually
remove it (and rework the save/restore code) once we get rid of the old
VGIC code.

Cheers,
Andre.

>> +	/* Number of list registers on this CPU */
>> +	int		nr_lr;
>> +
>> +	unsigned int used_lrs;
>> +	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
>> +
>> +	spinlock_t ap_list_lock;	/* Protects the ap_list */
>> +
>> +	/* list of IRQs for this VCPU to consider */
> 
> /*
>  * List of IRQs that this VCPU should consider because they are either
>  * Active or Pending (hence the name; AP list), or because they recently
>  * were one of the two and need to be migrated off this list to another
>  * VCPU.
>  */
> 
>> +	struct list_head ap_list_head;
>> +};
>> +
>> +#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>> +#define vgic_initialized(k)	(false)
>> +#define vgic_ready(k)		((k)->arch.vgic.ready)
>> +#define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>> +			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>> +
>> +/**
>> + * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>> + *
>> + * The host's GIC naturally limits the maximum amount of VCPUs a guest
>> + * can use.
>> + */
>> +static inline int kvm_vgic_get_max_vcpus(void)
>> +{
>> +	return kvm_vgic_global_state.max_gic_vcpus;
>> +}
>> +
>> +#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
>> -- 
>> 2.7.3
>>
> 
> Thanks,
> -Christoffer
> 

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

* Re: [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-03-29 21:16     ` Christoffer Dall
@ 2016-04-05 17:28       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-05 17:28 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 29/03/16 22:16, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:29AM +0000, Andre Przywara wrote:
>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>
>> Provide a vgic_queue_irq() function which decides whether a given
>> IRQ needs to be queued to a VCPU's ap_list.
>> This should be called whenever an IRQ became pending or got enabled,
> 
> becomes pending or enabled,
> 
>> either as a result of userspace injection, from in-kernel emulated
>> devices like the architected timer or from MMIO accesses to the
>> distributor emulation.
>> Also provides the necessary functions to allow userland to inject an
>> IRQ to a guest.
> 
> Since this is the first code that starts using our locking mechanism, we
> add some (hopefully) clear documentation of our locking strategy and
> requirements along with this patch.
> 
>> [Andre: refactor out vgic_queue_irq()]
>>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h  |   3 +
>>  virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h |   1 +
>>  3 files changed, 185 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 659f8b1..f32b284 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -178,6 +178,9 @@ struct vgic_cpu {
>>  	struct list_head ap_list_head;
>>  };
>>  
>> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>> +			bool level);
>> +
>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>>  #define vgic_initialized(k)	(false)
>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 8e34916..a95aabc 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -19,8 +19,25 @@
>>  
>>  #include "vgic.h"
>>  
>> +#define CREATE_TRACE_POINTS
>> +#include "../trace.h"
>> +
>>  struct vgic_global kvm_vgic_global_state;
>>  
>> +/*
>> + * Locking order is always:
>> + *   vgic_cpu->ap_list_lock
>> + *     vgic_irq->irq_lock
>> + *
>> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
>> + *
>> + * When taking more than one ap_list_lock at the same time, always take the
>> + * lowest numbered VCPU's ap_list_lock first, so:
>> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
>> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
>> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
>> + */
>> +
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid)
>>  {
>> @@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>>  	return NULL;
>>  }
>> +
>> +/**
>> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
>> + *
>> + * @irq:	The irq to route. Must be already locked.

                                  ^^^^^^^^^^^^^^^^^^^^^^

>> + *
>> + * Based on the current state of the interrupt (enabled, pending,
>> + * active, vcpu and target_vcpu), compute the next vcpu this should be
>> + * given to. Return NULL if this shouldn't be injected at all.
>> + */
>> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
>> +{
>> +	/* If the interrupt is active, it must stay on the current vcpu */
>> +	if (irq->active)
>> +		return irq->vcpu;
> 
> we are not taking a lock here.  What are the locking expectations?  If
> the expectarions are that the IRQ is locked when calling this function,
> can we have a BIG FAT COMMENT saying that then?

Do you mean really BIG FAT or is the above sufficient? (I guess not).
I will make it more prominent.

> It seems to me that we are somehow expecting irq->active and irq->vcpu
> to be in sync, but that's not necessarily the case if the IRQ is not
> locked.
> 
>> +
>> +	/* If enabled and pending, it can migrate to a new one */
> 
> I think this comment should be rewritten to:
> 
> If the IRQ is not active but enabled and pending, we should direct it to
> its configured target VCPU.
> 
>> +	if (irq->enabled && irq->pending)
>> +		return irq->target_vcpu;
>> +
>> +	/* Otherwise, it is considered idle */
> 
> not sure what idle means here, I suggest something like:
> 
> If neither active nor pending and enabled, then this IRQ should not be
> queued to any VCPU.
> 
>> +	return NULL;
>> +}
>> +
>> +/*
>> + * Only valid injection if changing level for level-triggered IRQs or for a
>> + * rising edge.
>> + */
>> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
>> +{
>> +	switch (irq->config) {
>> +	case VGIC_CONFIG_LEVEL:
>> +		return irq->line_level != level;
>> +	case VGIC_CONFIG_EDGE:
>> +		return level;
>> +	default:
>> +		BUG();
> 
> is the default case there for making the compiler happy or can we just
> get rid of it?

Just removing it was fine (for GCC 5.3.0, at least).

>> +	}
>> +}
>> +
>> +/*
>> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
>> + * Do the queuing if necessary, taking the right locks in the right order.
>> + * Returns true when the IRQ was queued, false otherwise.
>> + *
>> + * Needs to be entered with the IRQ lock already held, but will return
>> + * with all locks dropped.
>> + */
>> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)
> 
> should we name this vgic_try_queue_irq_locked ?

Mmh, since it (re-)tries quite hard I am not sure _try_ would be
misleading. Basically it queues the IRQ whenever possible and/or
sensible. Having _unlock in it like you suggested in another reply makes
more sense, I think.

>> +{
>> +	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);
> 
> should we have something like BUG_ON(!spin_is_locked(irq->irq_lock));
> here?
> 
> Not sure if there's some bug checking here which is only emitted if a
> user select CONFIG_CHECK_SOME_LOCKING_THINGS that we could use...?

There is CONFIG_DEBUG_SPINLOCK, but I couldn't find some conditional
debug macro suitable for the purpose. I defined one now for the file
only (since we have quite some users here).

>> +
>> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
>> +		/*
>> +		 * If this IRQ is already on a VCPU's ap_list, then it
>> +		 * cannot be moved or modified and there is no more work for
>> +		 * us to do.
>> +		 *
>> +		 * Otherwise, if the irq is not pending and enabled, it does
>> +		 * not need to be inserted into an ap_list and there is also
>> +		 * no more work for us to do.
>> +		 */
> 
> is the !vcpu check here not redundant because if you ever get to
> evaluating it, then irq->vcpu is null, and pending and enabled are set,
> which means the oracle couldn't have returned null, could it?

In this case vcpu is always irq->target_vcpu, if I did the math
correctly. So can this be NULL?
Even if this is correct reasoning, I wonder if we optimize something
prematurely here and rely on the current implementation of
vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
NULL pointer deference below (in the first spin_lock after the retry:
label), so I'd rather keep this explicit check in here.

> that would also explain why we don't have to re-check the same
> conditions below...
> 
> or am I getting this wrong, because you could also have someone
> explicitly setting the IRQ to active via trapped MMIO, in which case we
> should be able to queue it without it being pending && enabled, which
> would indicate that it's the other way around, you should only evaluate
> !vcpu and kup the !(pending && enabled) part....?

You lost me here, which hints at the fragility of this optimization ;-)

>> +		spin_unlock(&irq->irq_lock);
>> +		return false;
>> +	}
>> +
>> +	/*
>> +	 * We must unlock the irq lock to take the ap_list_lock where
>> +	 * we are going to insert this new pending interrupt.
>> +	 */
>> +	spin_unlock(&irq->irq_lock);
>> +
>> +	/* someone can do stuff here, which we re-check below */
>> +retry:
>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +	spin_lock(&irq->irq_lock);
>> +
>> +	/*
>> +	 * Did something change behind our backs?
>> +	 *
>> +	 * There are two cases:
>> +	 * 1) The irq became pending or active behind our backs and/or
>> +	 *    the irq->vcpu field was set correspondingly when putting
>> +	 *    the irq on an ap_list. Then drop the locks and return.
>> +	 * 2) Someone changed the affinity on this irq behind our
>> +	 *    backs and we are now holding the wrong ap_list_lock.
>> +	 *    Then drop the locks and try the new VCPU.
>> +	 */
>> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
> 
> here I'm concerned about the active state again.

Mmmh, can you elaborate and sketch a case where the active state would
cause trouble? This check is just here to avoid iterating on a no longer
pending or enabled IRQ. I wonder if an active IRQ can really sneak into
this function here in the first place?

> I feel like something more similar to my initial version of this patch
> is what we really want:
> 
>        if (irq->vcpu || vcpu != vgic_target_oracle(irq))
>            goto real_retry;
> 
> and read_retry is then a label at the very top of this function, before
> the initial call to vgic_target_oracle()....
> 
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +		return false;
>> +	}
>> +
>> +	if (irq->target_vcpu != vcpu) {
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +
>> +		vcpu = irq->target_vcpu;
>> +		goto retry;
>> +	}
>> +
>> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
>> +	irq->vcpu = vcpu;
>> +
>> +	spin_unlock(&irq->irq_lock);
>> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +
>> +	kvm_vcpu_kick(vcpu);
>> +
>> +	return true;
>> +}
>> +
>> +static void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +				    u32 intid, bool level)
>> +{
>> +	struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
>> +
>> +	trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
>> +
>> +	BUG_ON(in_interrupt());
> 
> I don't remember why we thought it was a good idea to have this BUG_ON()
> anymore.  Anyone?

Me neither. Is that because of the case where "kvm_notify_acked_irq
calls kvm_set_irq" (which in turn may call this function)?
I am happy to remove it, also as the old VGIC doesn't seem to have it.

>> +
>> +	spin_lock(&irq->irq_lock);
>> +
>> +	if (!vgic_validate_injection(irq, level)) {
>> +		/* Nothing to see here, move along... */
>> +		spin_unlock(&irq->irq_lock);
>> +		return;
>> +	}
>> +
>> +	if (irq->config == VGIC_CONFIG_LEVEL) {
>> +		irq->line_level = level;
>> +		irq->pending = level || irq->soft_pending;
>> +	} else {
>> +		irq->pending = true;
>> +	}
>> +
>> +	vgic_queue_irq(kvm, irq);
>> +}
>> +
>> +/**
>> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
>> + * @kvm:     The VM structure pointer
>> + * @cpuid:   The CPU for PPIs
>> + * @intid:   The INTID to inject a new state to.
>> + *           must not be mapped to a HW interrupt.
> 
> stray line here?  I don't understand this bit about 'must not be mapped'
> and I think that should be moved to the explanation below with some
> rationale, and if important, perhaps guarded with a BUG_ON() ?

I think this is a copy&paste leftover from the old VGIC with the old way
of handling mapped IRQs. Actually the implementations of
kvm_vgic_inject_irq() and kvm_vgic_inject_mapped_irq() are now
identical, so the former differentiation does not apply anymore. I will
#define the latter to the former for the new VGIC and we should schedule
the removal of the the "mapped" version when the old VGIC gets removed.

Btw: Are we OK with marking those cases which deserve some rework after
the old VGIC is gone with some kind of TODO comments?

Cheers,
Andre.

> 
>> + * @level:   Edge-triggered:  true:  to trigger the interrupt
>> + *			      false: to ignore the call
>> + *	     Level-sensitive  true:  raise the input signal
>> + *			      false: lower the input signal
>> + *
>> + * The GIC is not concerned with devices being active-LOW or active-HIGH for
> 
> We should probably write VGIC here instead of GIC, just to avoid
> confusion.
> 
>> + * level-sensitive interrupts.  You can think of the level parameter as 1
>> + * being HIGH and 0 being LOW and all devices being active-HIGH.
>> + */
>> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>> +			bool level)
>> +{
>> +	struct kvm_vcpu *vcpu;
>> +
>> +	vcpu = kvm_get_vcpu(kvm, cpuid);
>> +	vgic_update_irq_pending(kvm, vcpu, intid, level);
>> +	return 0;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 61b8d22..e9f4aa6 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -18,5 +18,6 @@
>>  
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid);
>> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>>  
>>  #endif
>> -- 
>> 2.7.3
>>
> 
> Otherwise the split between update/queue looks reasonable here.
> 
> Btw., anywhere where I write 'you' in this mail, I mean 'we' and take
> partial blame for any bugs here :)
> 
> Thanks,
> -Christoffer
> 

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

* [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-04-05 17:28       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-05 17:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 29/03/16 22:16, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:29AM +0000, Andre Przywara wrote:
>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>
>> Provide a vgic_queue_irq() function which decides whether a given
>> IRQ needs to be queued to a VCPU's ap_list.
>> This should be called whenever an IRQ became pending or got enabled,
> 
> becomes pending or enabled,
> 
>> either as a result of userspace injection, from in-kernel emulated
>> devices like the architected timer or from MMIO accesses to the
>> distributor emulation.
>> Also provides the necessary functions to allow userland to inject an
>> IRQ to a guest.
> 
> Since this is the first code that starts using our locking mechanism, we
> add some (hopefully) clear documentation of our locking strategy and
> requirements along with this patch.
> 
>> [Andre: refactor out vgic_queue_irq()]
>>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h  |   3 +
>>  virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h |   1 +
>>  3 files changed, 185 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 659f8b1..f32b284 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -178,6 +178,9 @@ struct vgic_cpu {
>>  	struct list_head ap_list_head;
>>  };
>>  
>> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>> +			bool level);
>> +
>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>>  #define vgic_initialized(k)	(false)
>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 8e34916..a95aabc 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -19,8 +19,25 @@
>>  
>>  #include "vgic.h"
>>  
>> +#define CREATE_TRACE_POINTS
>> +#include "../trace.h"
>> +
>>  struct vgic_global kvm_vgic_global_state;
>>  
>> +/*
>> + * Locking order is always:
>> + *   vgic_cpu->ap_list_lock
>> + *     vgic_irq->irq_lock
>> + *
>> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
>> + *
>> + * When taking more than one ap_list_lock at the same time, always take the
>> + * lowest numbered VCPU's ap_list_lock first, so:
>> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
>> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
>> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
>> + */
>> +
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid)
>>  {
>> @@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>>  	return NULL;
>>  }
>> +
>> +/**
>> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
>> + *
>> + * @irq:	The irq to route. Must be already locked.

                                  ^^^^^^^^^^^^^^^^^^^^^^

>> + *
>> + * Based on the current state of the interrupt (enabled, pending,
>> + * active, vcpu and target_vcpu), compute the next vcpu this should be
>> + * given to. Return NULL if this shouldn't be injected at all.
>> + */
>> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
>> +{
>> +	/* If the interrupt is active, it must stay on the current vcpu */
>> +	if (irq->active)
>> +		return irq->vcpu;
> 
> we are not taking a lock here.  What are the locking expectations?  If
> the expectarions are that the IRQ is locked when calling this function,
> can we have a BIG FAT COMMENT saying that then?

Do you mean really BIG FAT or is the above sufficient? (I guess not).
I will make it more prominent.

> It seems to me that we are somehow expecting irq->active and irq->vcpu
> to be in sync, but that's not necessarily the case if the IRQ is not
> locked.
> 
>> +
>> +	/* If enabled and pending, it can migrate to a new one */
> 
> I think this comment should be rewritten to:
> 
> If the IRQ is not active but enabled and pending, we should direct it to
> its configured target VCPU.
> 
>> +	if (irq->enabled && irq->pending)
>> +		return irq->target_vcpu;
>> +
>> +	/* Otherwise, it is considered idle */
> 
> not sure what idle means here, I suggest something like:
> 
> If neither active nor pending and enabled, then this IRQ should not be
> queued to any VCPU.
> 
>> +	return NULL;
>> +}
>> +
>> +/*
>> + * Only valid injection if changing level for level-triggered IRQs or for a
>> + * rising edge.
>> + */
>> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
>> +{
>> +	switch (irq->config) {
>> +	case VGIC_CONFIG_LEVEL:
>> +		return irq->line_level != level;
>> +	case VGIC_CONFIG_EDGE:
>> +		return level;
>> +	default:
>> +		BUG();
> 
> is the default case there for making the compiler happy or can we just
> get rid of it?

Just removing it was fine (for GCC 5.3.0, at least).

>> +	}
>> +}
>> +
>> +/*
>> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
>> + * Do the queuing if necessary, taking the right locks in the right order.
>> + * Returns true when the IRQ was queued, false otherwise.
>> + *
>> + * Needs to be entered with the IRQ lock already held, but will return
>> + * with all locks dropped.
>> + */
>> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)
> 
> should we name this vgic_try_queue_irq_locked ?

Mmh, since it (re-)tries quite hard I am not sure _try_ would be
misleading. Basically it queues the IRQ whenever possible and/or
sensible. Having _unlock in it like you suggested in another reply makes
more sense, I think.

>> +{
>> +	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);
> 
> should we have something like BUG_ON(!spin_is_locked(irq->irq_lock));
> here?
> 
> Not sure if there's some bug checking here which is only emitted if a
> user select CONFIG_CHECK_SOME_LOCKING_THINGS that we could use...?

There is CONFIG_DEBUG_SPINLOCK, but I couldn't find some conditional
debug macro suitable for the purpose. I defined one now for the file
only (since we have quite some users here).

>> +
>> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
>> +		/*
>> +		 * If this IRQ is already on a VCPU's ap_list, then it
>> +		 * cannot be moved or modified and there is no more work for
>> +		 * us to do.
>> +		 *
>> +		 * Otherwise, if the irq is not pending and enabled, it does
>> +		 * not need to be inserted into an ap_list and there is also
>> +		 * no more work for us to do.
>> +		 */
> 
> is the !vcpu check here not redundant because if you ever get to
> evaluating it, then irq->vcpu is null, and pending and enabled are set,
> which means the oracle couldn't have returned null, could it?

In this case vcpu is always irq->target_vcpu, if I did the math
correctly. So can this be NULL?
Even if this is correct reasoning, I wonder if we optimize something
prematurely here and rely on the current implementation of
vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
NULL pointer deference below (in the first spin_lock after the retry:
label), so I'd rather keep this explicit check in here.

> that would also explain why we don't have to re-check the same
> conditions below...
> 
> or am I getting this wrong, because you could also have someone
> explicitly setting the IRQ to active via trapped MMIO, in which case we
> should be able to queue it without it being pending && enabled, which
> would indicate that it's the other way around, you should only evaluate
> !vcpu and kup the !(pending && enabled) part....?

You lost me here, which hints at the fragility of this optimization ;-)

>> +		spin_unlock(&irq->irq_lock);
>> +		return false;
>> +	}
>> +
>> +	/*
>> +	 * We must unlock the irq lock to take the ap_list_lock where
>> +	 * we are going to insert this new pending interrupt.
>> +	 */
>> +	spin_unlock(&irq->irq_lock);
>> +
>> +	/* someone can do stuff here, which we re-check below */
>> +retry:
>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +	spin_lock(&irq->irq_lock);
>> +
>> +	/*
>> +	 * Did something change behind our backs?
>> +	 *
>> +	 * There are two cases:
>> +	 * 1) The irq became pending or active behind our backs and/or
>> +	 *    the irq->vcpu field was set correspondingly when putting
>> +	 *    the irq on an ap_list. Then drop the locks and return.
>> +	 * 2) Someone changed the affinity on this irq behind our
>> +	 *    backs and we are now holding the wrong ap_list_lock.
>> +	 *    Then drop the locks and try the new VCPU.
>> +	 */
>> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
> 
> here I'm concerned about the active state again.

Mmmh, can you elaborate and sketch a case where the active state would
cause trouble? This check is just here to avoid iterating on a no longer
pending or enabled IRQ. I wonder if an active IRQ can really sneak into
this function here in the first place?

> I feel like something more similar to my initial version of this patch
> is what we really want:
> 
>        if (irq->vcpu || vcpu != vgic_target_oracle(irq))
>            goto real_retry;
> 
> and read_retry is then a label at the very top of this function, before
> the initial call to vgic_target_oracle()....
> 
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +		return false;
>> +	}
>> +
>> +	if (irq->target_vcpu != vcpu) {
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +
>> +		vcpu = irq->target_vcpu;
>> +		goto retry;
>> +	}
>> +
>> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
>> +	irq->vcpu = vcpu;
>> +
>> +	spin_unlock(&irq->irq_lock);
>> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +
>> +	kvm_vcpu_kick(vcpu);
>> +
>> +	return true;
>> +}
>> +
>> +static void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +				    u32 intid, bool level)
>> +{
>> +	struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
>> +
>> +	trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
>> +
>> +	BUG_ON(in_interrupt());
> 
> I don't remember why we thought it was a good idea to have this BUG_ON()
> anymore.  Anyone?

Me neither. Is that because of the case where "kvm_notify_acked_irq
calls kvm_set_irq" (which in turn may call this function)?
I am happy to remove it, also as the old VGIC doesn't seem to have it.

>> +
>> +	spin_lock(&irq->irq_lock);
>> +
>> +	if (!vgic_validate_injection(irq, level)) {
>> +		/* Nothing to see here, move along... */
>> +		spin_unlock(&irq->irq_lock);
>> +		return;
>> +	}
>> +
>> +	if (irq->config == VGIC_CONFIG_LEVEL) {
>> +		irq->line_level = level;
>> +		irq->pending = level || irq->soft_pending;
>> +	} else {
>> +		irq->pending = true;
>> +	}
>> +
>> +	vgic_queue_irq(kvm, irq);
>> +}
>> +
>> +/**
>> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
>> + * @kvm:     The VM structure pointer
>> + * @cpuid:   The CPU for PPIs
>> + * @intid:   The INTID to inject a new state to.
>> + *           must not be mapped to a HW interrupt.
> 
> stray line here?  I don't understand this bit about 'must not be mapped'
> and I think that should be moved to the explanation below with some
> rationale, and if important, perhaps guarded with a BUG_ON() ?

I think this is a copy&paste leftover from the old VGIC with the old way
of handling mapped IRQs. Actually the implementations of
kvm_vgic_inject_irq() and kvm_vgic_inject_mapped_irq() are now
identical, so the former differentiation does not apply anymore. I will
#define the latter to the former for the new VGIC and we should schedule
the removal of the the "mapped" version when the old VGIC gets removed.

Btw: Are we OK with marking those cases which deserve some rework after
the old VGIC is gone with some kind of TODO comments?

Cheers,
Andre.

> 
>> + * @level:   Edge-triggered:  true:  to trigger the interrupt
>> + *			      false: to ignore the call
>> + *	     Level-sensitive  true:  raise the input signal
>> + *			      false: lower the input signal
>> + *
>> + * The GIC is not concerned with devices being active-LOW or active-HIGH for
> 
> We should probably write VGIC here instead of GIC, just to avoid
> confusion.
> 
>> + * level-sensitive interrupts.  You can think of the level parameter as 1
>> + * being HIGH and 0 being LOW and all devices being active-HIGH.
>> + */
>> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>> +			bool level)
>> +{
>> +	struct kvm_vcpu *vcpu;
>> +
>> +	vcpu = kvm_get_vcpu(kvm, cpuid);
>> +	vgic_update_irq_pending(kvm, vcpu, intid, level);
>> +	return 0;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 61b8d22..e9f4aa6 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -18,5 +18,6 @@
>>  
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid);
>> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>>  
>>  #endif
>> -- 
>> 2.7.3
>>
> 
> Otherwise the split between update/queue looks reasonable here.
> 
> Btw., anywhere where I write 'you' in this mail, I mean 'we' and take
> partial blame for any bugs here :)
> 
> Thanks,
> -Christoffer
> 

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

* Re: [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
  2016-03-30 13:53     ` Christoffer Dall
@ 2016-04-05 17:57       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-05 17:57 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 30/03/16 14:53, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Implement the functionality for syncing IRQs between our emulation
>> and the list registers, which represent the guest's view of IRQs.
>> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
>> which gets called on guest entry and exit.
> 
> I thought we agreed to split this up in a generic part and then GICv2
> and GICv3 parts following, but ok, I'll look through this code, but I
> strongly suggest splitting it up for the next posting.

Right, I guess I missed this one. I abandoned the idea of splitting the
patch _series_ between a v2 and a v3 series (to avoid agreeing on the v2
implementation too early without taking the v3 requirements into
account), so I guess I skipped the comment about this patch split.
I will try to split off the generic part of the code.

>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h     |   4 +
>>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h    |   4 +
>>  4 files changed, 373 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index f32b284..986f23f 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>>  
>> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>> +
>>  /**
>>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>>   *
>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>> index 0bf6f27..1cec423 100644
>> --- a/virt/kvm/arm/vgic/vgic-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>> @@ -14,11 +14,172 @@
>>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>   */
>>  
>> +#include <linux/irqchip/arm-gic.h>
>>  #include <linux/kvm.h>
>>  #include <linux/kvm_host.h>
>>  
>>  #include "vgic.h"
>>  
>> +/*
>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>> + *
>> + * Warning: Calling this function may modify *val.
>> + */
>> +static unsigned long *u64_to_bitmask(u64 *val)
>> +{
>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>> +	*val = (*val >> 32) | (*val << 32);
>> +#endif
>> +	return (unsigned long *)val;
>> +}
>> +
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>> +		u64 eisr = cpuif->vgic_eisr;
>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
>> +			struct vgic_irq *irq;
>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>> +
>> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>> +
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
>> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
> 
> we just had a warning above if the LR state was set, so how do we
> expect this to be modified in the mean time?

I guess the warning is just a warning, so code execution continues in
this case, right?

> The following line caters for the famous hardware race, right?  If so, I think it deserved a comment:
> 
> /*
>  * The hardware doesn't guarantee that the LR's bit is set in the ELRSR
>  * despite the virtual interrupt being EOIed and generating a
>  * maintenance interrupt.  Force the bit to be set.
>  */
> 
>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>> +		}
>> +	}
>> +
>> +	/* check and disable underflow maintenance IRQ */
> 
> s/check and d/D/
> 
>> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> 
> I think the above should be moved to fold_lr_state
> 
>> +
>> +	/*
>> +	 * In the next iterations of the vcpu loop, if we sync the
>> +	 * vgic state after flushing it, but before entering the guest
>> +	 * (this happens for pending signals and vmid rollovers), then
>> +	 * make sure we don't pick up any old maintenance interrupts
>> +	 * here.
>> +	 */
>> +	cpuif->vgic_eisr = 0;
>> +}
>> +
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
>> +}
>> +
>> +/*
>> + * transfer the content of the LRs back into the corresponding ap_list:
>> + * - active bit is transferred as is
>> + * - pending bit is
>> + *   - transferred as is in case of edge sensitive IRQs
>> + *   - set to the line-level (resample time) for level sensitive IRQs
>> + */
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +	int lr;
>> +
>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>> +		u32 val = cpuif->vgic_lr[lr];
>> +		u32 intid = val & GICH_LR_VIRTUALID;
>> +		struct vgic_irq *irq;
>> +
>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/* Always preserve the active bit */
>> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
>> +
>> +		/* Edge is the only case where we preserve the pending bit */
>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>> +		    (val & GICH_LR_PENDING_BIT)) {
>> +			irq->pending = true;
>> +
>> +			if (intid < VGIC_NR_SGIS) {
>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>> +
>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> 
> Are we happy with relying on all the remaining bits being 0 here or
> should we define a proper CPUID mask?

Not sure which remaining bits you mean? GICH_LR_PHYSID_CPUID is a mask
(admittedly a bit misnamed).
Or what do I miss here?

>> +				irq->source |= (1 << cpuid);
>> +			}
>> +		}
>> +
>> +		/* Clear soft pending state when level IRQs have been acked */
>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>> +		    !(val & GICH_LR_PENDING_BIT)) {
>> +			irq->soft_pending = false;
>> +			irq->pending = irq->line_level;
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +}
>> +
>> +/*
>> + * Populates the particular LR with the state of a given IRQ:
>> + * - for an edge sensitive IRQ the pending state is reset in the struct
> 
> s/reset/cleared/
> s/the struct/the vgic_irq struct/
> 
>> + * - for a level sensitive IRQ the pending state value is unchanged;
>> + *   it will be resampled on deactivation
> 
> s/
> it will be resampled on deactivation/
> it is dictated directly by the input level/
> 
>> + *
>> + * If irq is not NULL, the irq_lock must be hold already by the caller.
> 
> s/hold/held/
> 
>> + * If irq is NULL, the respective LR gets cleared.
> 
> If @irq describes an SGI with multiple sources, we choose the
> lowest-numbered source VCPU and clear that bit in the source bitmap.
> 
>> + */
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>> +{
>> +	u32 val;
>> +
>> +	if (!irq) {
>> +		val = 0;
>> +		goto out;
>> +	}
> 
> I'm not convinced about keeping this functionality in this function.
> 
> Wouldn't it be much more clear to have vgic_clear_lr() as a separate
> function?

Yeah, I agree. Also found it cumbersome to explicitly call this function
with a NULL argument to clear it.

>> +
>> +	val = irq->intid;
>> +
>> +	if (irq->pending) {
>> +		val |= GICH_LR_PENDING_BIT;
>> +
>> +		if (irq->config == VGIC_CONFIG_EDGE)
>> +			irq->pending = false;
>> +
>> +		if (irq->intid < VGIC_NR_SGIS) {
>> +			u32 src = ffs(irq->source);
> 
> can't you do src = __ffs(irq->source) here to avoid the (src - 1) below?
> 
>> +
>> +			BUG_ON(!src);
>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>> +			irq->source &= ~(1 << (src - 1));
>> +			if (irq->source)
>> +				irq->pending = true;
>> +		}
>> +	}
>> +
>> +	if (irq->active)
>> +		val |= GICH_LR_ACTIVE_BIT;
>> +
>> +	if (irq->hw) {
>> +		val |= GICH_LR_HW;
>> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
>> +	} else {
>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>> +			val |= GICH_LR_EOI;
>> +	}
>> +
>> +out:
>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
>> +}
>> +
>>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>>  {
>>  	struct vgic_dist *dist = &kvm->arch.vgic;
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 29c753e..90a85bf 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>>  	return 0;
>>  }
>> +
>> +/**
>> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
>> + *
>> + * @vcpu: The VCPU pointer
>> + *
>> + * Go over the list of "interesting" interrupts, and prune those that we
>> + * won't have to consider in the near future.
>> + */
>> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq, *tmp;
>> +
>> +retry:
>> +	spin_lock(&vgic_cpu->ap_list_lock);
>> +
>> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
>> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		BUG_ON(vcpu != irq->vcpu);
>> +
>> +		target_vcpu = vgic_target_oracle(irq);
>> +
>> +		if (!target_vcpu) {
>> +			/*
>> +			 * We don't need to process this interrupt any
>> +			 * further, move it off the list.
>> +			 */
>> +			list_del_init(&irq->ap_list);
> 
> why list_del_init and not list_del here?  do we ever do list_empty() on
> the &irq->ap_list ?

Why not? I think we discussed the usage of list_empty() for determining
if the VCPU is ready to run.
What is your concern about list_del_init? Is that too costly?

>> +			irq->vcpu = NULL;
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		if (target_vcpu == vcpu) {
>> +			/* We're on the right CPU */
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		/* This interrupt looks like it has to be migrated. */
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vgic_cpu->ap_list_lock);
>> +
>> +		/*
>> +		 * Ensure locking order by always locking the smallest
>> +		 * ID first.
>> +		 */
>> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
>> +			vcpuA = vcpu;
>> +			vcpuB = target_vcpu;
>> +		} else {
>> +			vcpuA = target_vcpu;
>> +			vcpuB = vcpu;
>> +		}
>> +
>> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/*
>> +		 * If the affinity has been preserved, move the
>> +		 * interrupt around. Otherwise, it means things have
>> +		 * changed while the interrupt was unlocked, and we
>> +		 * need to replay this.
>> +		 *
>> +		 * In all cases, we cannot trust the list not to have
>> +		 * changed, so we restart from the beginning.
>> +		 */
>> +		if (target_vcpu == vgic_target_oracle(irq)) {
>> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
>> +
>> +			list_del_init(&irq->ap_list);
> 
> again, why list_del_init and not just list_del ?
> 
>> +			irq->vcpu = target_vcpu;
>> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		goto retry;
>> +	}
>> +
>> +	spin_unlock(&vgic_cpu->ap_list_lock);
>> +}
>> +
>> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_process_maintenance(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_fold_lr_state(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +/*
>> + * Requires the ap_lock to be held.
>> + * If irq is not NULL, requires the IRQ lock to be held as well.
>> + * If irq is NULL, the list register gets cleared.
>> + */
>> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>> +				    struct vgic_irq *irq, int lr)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_populate_lr(vcpu, irq, lr);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_set_underflow(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq;
>> +	int count = 0;
>> +
>> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
>> +		spin_lock(&irq->irq_lock);
>> +		/* GICv2 SGIs can count for more than one... */
>> +		if (irq->intid < VGIC_NR_SGIS && irq->source)
> 
> how can we have an SGI on an AP list without the irq->source field set?
> 
> Is the irq->source check to cater for GICv3?

Yes, in the v3 case irq->source is 0, so the hweight is zero as well.

>> +			count += hweight8(irq->source);
>> +		else
>> +			count++;
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +	return count;
> 
> this does feel like an awful lot of code on each entry.

Is this really a lot of code? I count two comparisons and an inc, or the
hweight8 in case of SGIs. The latter implementation doesn't look to bad
either (given that it all happens in a register).
Or is there some code I missed?

> I'm wondering
> if we should have a count on each vgic_cpu containing the length of the
> AP list which is then adjusted via the queue and removal functions?

That sounds like some work to make sure we cover all the cases. Also we
would need to care about the consistency of this.

>> +}
>> +
>> +/* requires the vcpu ap_lock to be held */
> 
> s/ap_lock/ap_list_lock/
> 
>> +static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
> 
> I'm not in love with the fact that we have two separate functions named:
> 
>   vgic_populate_lrs  and
>   vgic_populate_lr
> 
> perhaps this could be changed to 'vgic_flush_ap_list' ?

Agreed.

> 
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +	struct vgic_irq *irq;
>> +	int count = 0;
>> +
>> +	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
>> +		vgic_set_underflow(vcpu);
>> +		vgic_sort_ap_list(vcpu);
>> +	}
>> +
>> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
>> +			goto next;
>> +
>> +		/*
>> +		 * If we get an SGI with multiple sources, try to get
>> +		 * them in all at once.
>> +		 */
>> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
>> +		    irq->intid < VGIC_NR_SGIS) {
> 
> I wonder if a lot of this code would be more readable if we added and
> used the following primitives:
> vgic_irq_is_sgi()
> vgic_irq_is_ppi()
> vgic_irq_is_spi()

If that doesn't break 80 characters ... ;-)

>> +			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
>> +				vgic_populate_lr(vcpu, irq, count++);
>> +		} else {
>> +			vgic_populate_lr(vcpu, irq, count++);
>> +		}
> 
> this stuff about the SGIs is really dense, so I'm wondering if it's more
> clean to make it even more dense and rewrite the whole if-statement to:
> 
> 	do {
> 		vgic_populate(vcpu, irq, count++);
> 	} while (irq->source && count < vgic.nr_lr);
> 
> (btw. I believe all these places referencing the nr_lr in the vgic_cpu
> struct could use the global state structure instead).

Good point. We should convert all the places where this is easily doable
already.

> 
>> +
>> +next:
>> +		spin_unlock(&irq->irq_lock);
>> +
>> +		if (count == vcpu->arch.vgic_cpu.nr_lr)
>> +			break;
>> +	}
>> +
>> +	vcpu->arch.vgic_cpu.used_lrs = count;
>> +
>> +	/* Nuke remaining LRs */
>> +	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
>> +		vgic_populate_lr(vcpu, NULL, count);
> 
> should we not change this to adhere to the optimizations Marc
> implemented for the current VGIC (i.e. clear the LRs on sync+init, and
> only write what you need here)?

Those optimizations were not in the branch I based this series on.
I will take a look with the new series being based on 4.6-rc (added
live_lrs already).

Cheers,
Andre.

BTW: Thanks for the thorough review. I agree and will change all your
comments I didn't explicitly replied on.

> 
>> +}
>> +
>> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>> +{
>> +	vgic_process_maintenance_interrupt(vcpu);
>> +	vgic_fold_lr_state(vcpu);
>> +	vgic_prune_ap_list(vcpu);
>> +}
>> +
>> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>> +{
>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +	vgic_populate_lrs(vcpu);
>> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index b2faf00..95ef3cf 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -21,5 +21,9 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>>  
>>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>>  
>>  #endif
>> -- 
>> 2.7.3
>>
> 
> Thanks,
> -Christoffer
> 

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

* [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
@ 2016-04-05 17:57       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-05 17:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 30/03/16 14:53, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Implement the functionality for syncing IRQs between our emulation
>> and the list registers, which represent the guest's view of IRQs.
>> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
>> which gets called on guest entry and exit.
> 
> I thought we agreed to split this up in a generic part and then GICv2
> and GICv3 parts following, but ok, I'll look through this code, but I
> strongly suggest splitting it up for the next posting.

Right, I guess I missed this one. I abandoned the idea of splitting the
patch _series_ between a v2 and a v3 series (to avoid agreeing on the v2
implementation too early without taking the v3 requirements into
account), so I guess I skipped the comment about this patch split.
I will try to split off the generic part of the code.

>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h     |   4 +
>>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h    |   4 +
>>  4 files changed, 373 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index f32b284..986f23f 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>>  
>> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>> +
>>  /**
>>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>>   *
>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>> index 0bf6f27..1cec423 100644
>> --- a/virt/kvm/arm/vgic/vgic-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>> @@ -14,11 +14,172 @@
>>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>   */
>>  
>> +#include <linux/irqchip/arm-gic.h>
>>  #include <linux/kvm.h>
>>  #include <linux/kvm_host.h>
>>  
>>  #include "vgic.h"
>>  
>> +/*
>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>> + *
>> + * Warning: Calling this function may modify *val.
>> + */
>> +static unsigned long *u64_to_bitmask(u64 *val)
>> +{
>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>> +	*val = (*val >> 32) | (*val << 32);
>> +#endif
>> +	return (unsigned long *)val;
>> +}
>> +
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>> +		u64 eisr = cpuif->vgic_eisr;
>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
>> +			struct vgic_irq *irq;
>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>> +
>> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>> +
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
>> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
> 
> we just had a warning above if the LR state was set, so how do we
> expect this to be modified in the mean time?

I guess the warning is just a warning, so code execution continues in
this case, right?

> The following line caters for the famous hardware race, right?  If so, I think it deserved a comment:
> 
> /*
>  * The hardware doesn't guarantee that the LR's bit is set in the ELRSR
>  * despite the virtual interrupt being EOIed and generating a
>  * maintenance interrupt.  Force the bit to be set.
>  */
> 
>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>> +		}
>> +	}
>> +
>> +	/* check and disable underflow maintenance IRQ */
> 
> s/check and d/D/
> 
>> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> 
> I think the above should be moved to fold_lr_state
> 
>> +
>> +	/*
>> +	 * In the next iterations of the vcpu loop, if we sync the
>> +	 * vgic state after flushing it, but before entering the guest
>> +	 * (this happens for pending signals and vmid rollovers), then
>> +	 * make sure we don't pick up any old maintenance interrupts
>> +	 * here.
>> +	 */
>> +	cpuif->vgic_eisr = 0;
>> +}
>> +
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
>> +}
>> +
>> +/*
>> + * transfer the content of the LRs back into the corresponding ap_list:
>> + * - active bit is transferred as is
>> + * - pending bit is
>> + *   - transferred as is in case of edge sensitive IRQs
>> + *   - set to the line-level (resample time) for level sensitive IRQs
>> + */
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +	int lr;
>> +
>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>> +		u32 val = cpuif->vgic_lr[lr];
>> +		u32 intid = val & GICH_LR_VIRTUALID;
>> +		struct vgic_irq *irq;
>> +
>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/* Always preserve the active bit */
>> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
>> +
>> +		/* Edge is the only case where we preserve the pending bit */
>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>> +		    (val & GICH_LR_PENDING_BIT)) {
>> +			irq->pending = true;
>> +
>> +			if (intid < VGIC_NR_SGIS) {
>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>> +
>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> 
> Are we happy with relying on all the remaining bits being 0 here or
> should we define a proper CPUID mask?

Not sure which remaining bits you mean? GICH_LR_PHYSID_CPUID is a mask
(admittedly a bit misnamed).
Or what do I miss here?

>> +				irq->source |= (1 << cpuid);
>> +			}
>> +		}
>> +
>> +		/* Clear soft pending state when level IRQs have been acked */
>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>> +		    !(val & GICH_LR_PENDING_BIT)) {
>> +			irq->soft_pending = false;
>> +			irq->pending = irq->line_level;
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +}
>> +
>> +/*
>> + * Populates the particular LR with the state of a given IRQ:
>> + * - for an edge sensitive IRQ the pending state is reset in the struct
> 
> s/reset/cleared/
> s/the struct/the vgic_irq struct/
> 
>> + * - for a level sensitive IRQ the pending state value is unchanged;
>> + *   it will be resampled on deactivation
> 
> s/
> it will be resampled on deactivation/
> it is dictated directly by the input level/
> 
>> + *
>> + * If irq is not NULL, the irq_lock must be hold already by the caller.
> 
> s/hold/held/
> 
>> + * If irq is NULL, the respective LR gets cleared.
> 
> If @irq describes an SGI with multiple sources, we choose the
> lowest-numbered source VCPU and clear that bit in the source bitmap.
> 
>> + */
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>> +{
>> +	u32 val;
>> +
>> +	if (!irq) {
>> +		val = 0;
>> +		goto out;
>> +	}
> 
> I'm not convinced about keeping this functionality in this function.
> 
> Wouldn't it be much more clear to have vgic_clear_lr() as a separate
> function?

Yeah, I agree. Also found it cumbersome to explicitly call this function
with a NULL argument to clear it.

>> +
>> +	val = irq->intid;
>> +
>> +	if (irq->pending) {
>> +		val |= GICH_LR_PENDING_BIT;
>> +
>> +		if (irq->config == VGIC_CONFIG_EDGE)
>> +			irq->pending = false;
>> +
>> +		if (irq->intid < VGIC_NR_SGIS) {
>> +			u32 src = ffs(irq->source);
> 
> can't you do src = __ffs(irq->source) here to avoid the (src - 1) below?
> 
>> +
>> +			BUG_ON(!src);
>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>> +			irq->source &= ~(1 << (src - 1));
>> +			if (irq->source)
>> +				irq->pending = true;
>> +		}
>> +	}
>> +
>> +	if (irq->active)
>> +		val |= GICH_LR_ACTIVE_BIT;
>> +
>> +	if (irq->hw) {
>> +		val |= GICH_LR_HW;
>> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
>> +	} else {
>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>> +			val |= GICH_LR_EOI;
>> +	}
>> +
>> +out:
>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
>> +}
>> +
>>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>>  {
>>  	struct vgic_dist *dist = &kvm->arch.vgic;
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 29c753e..90a85bf 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>>  	return 0;
>>  }
>> +
>> +/**
>> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
>> + *
>> + * @vcpu: The VCPU pointer
>> + *
>> + * Go over the list of "interesting" interrupts, and prune those that we
>> + * won't have to consider in the near future.
>> + */
>> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq, *tmp;
>> +
>> +retry:
>> +	spin_lock(&vgic_cpu->ap_list_lock);
>> +
>> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
>> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		BUG_ON(vcpu != irq->vcpu);
>> +
>> +		target_vcpu = vgic_target_oracle(irq);
>> +
>> +		if (!target_vcpu) {
>> +			/*
>> +			 * We don't need to process this interrupt any
>> +			 * further, move it off the list.
>> +			 */
>> +			list_del_init(&irq->ap_list);
> 
> why list_del_init and not list_del here?  do we ever do list_empty() on
> the &irq->ap_list ?

Why not? I think we discussed the usage of list_empty() for determining
if the VCPU is ready to run.
What is your concern about list_del_init? Is that too costly?

>> +			irq->vcpu = NULL;
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		if (target_vcpu == vcpu) {
>> +			/* We're on the right CPU */
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		/* This interrupt looks like it has to be migrated. */
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vgic_cpu->ap_list_lock);
>> +
>> +		/*
>> +		 * Ensure locking order by always locking the smallest
>> +		 * ID first.
>> +		 */
>> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
>> +			vcpuA = vcpu;
>> +			vcpuB = target_vcpu;
>> +		} else {
>> +			vcpuA = target_vcpu;
>> +			vcpuB = vcpu;
>> +		}
>> +
>> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/*
>> +		 * If the affinity has been preserved, move the
>> +		 * interrupt around. Otherwise, it means things have
>> +		 * changed while the interrupt was unlocked, and we
>> +		 * need to replay this.
>> +		 *
>> +		 * In all cases, we cannot trust the list not to have
>> +		 * changed, so we restart from the beginning.
>> +		 */
>> +		if (target_vcpu == vgic_target_oracle(irq)) {
>> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
>> +
>> +			list_del_init(&irq->ap_list);
> 
> again, why list_del_init and not just list_del ?
> 
>> +			irq->vcpu = target_vcpu;
>> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		goto retry;
>> +	}
>> +
>> +	spin_unlock(&vgic_cpu->ap_list_lock);
>> +}
>> +
>> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_process_maintenance(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_fold_lr_state(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +/*
>> + * Requires the ap_lock to be held.
>> + * If irq is not NULL, requires the IRQ lock to be held as well.
>> + * If irq is NULL, the list register gets cleared.
>> + */
>> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>> +				    struct vgic_irq *irq, int lr)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_populate_lr(vcpu, irq, lr);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_set_underflow(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq;
>> +	int count = 0;
>> +
>> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
>> +		spin_lock(&irq->irq_lock);
>> +		/* GICv2 SGIs can count for more than one... */
>> +		if (irq->intid < VGIC_NR_SGIS && irq->source)
> 
> how can we have an SGI on an AP list without the irq->source field set?
> 
> Is the irq->source check to cater for GICv3?

Yes, in the v3 case irq->source is 0, so the hweight is zero as well.

>> +			count += hweight8(irq->source);
>> +		else
>> +			count++;
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +	return count;
> 
> this does feel like an awful lot of code on each entry.

Is this really a lot of code? I count two comparisons and an inc, or the
hweight8 in case of SGIs. The latter implementation doesn't look to bad
either (given that it all happens in a register).
Or is there some code I missed?

> I'm wondering
> if we should have a count on each vgic_cpu containing the length of the
> AP list which is then adjusted via the queue and removal functions?

That sounds like some work to make sure we cover all the cases. Also we
would need to care about the consistency of this.

>> +}
>> +
>> +/* requires the vcpu ap_lock to be held */
> 
> s/ap_lock/ap_list_lock/
> 
>> +static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
> 
> I'm not in love with the fact that we have two separate functions named:
> 
>   vgic_populate_lrs  and
>   vgic_populate_lr
> 
> perhaps this could be changed to 'vgic_flush_ap_list' ?

Agreed.

> 
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +	struct vgic_irq *irq;
>> +	int count = 0;
>> +
>> +	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
>> +		vgic_set_underflow(vcpu);
>> +		vgic_sort_ap_list(vcpu);
>> +	}
>> +
>> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
>> +			goto next;
>> +
>> +		/*
>> +		 * If we get an SGI with multiple sources, try to get
>> +		 * them in all at once.
>> +		 */
>> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
>> +		    irq->intid < VGIC_NR_SGIS) {
> 
> I wonder if a lot of this code would be more readable if we added and
> used the following primitives:
> vgic_irq_is_sgi()
> vgic_irq_is_ppi()
> vgic_irq_is_spi()

If that doesn't break 80 characters ... ;-)

>> +			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
>> +				vgic_populate_lr(vcpu, irq, count++);
>> +		} else {
>> +			vgic_populate_lr(vcpu, irq, count++);
>> +		}
> 
> this stuff about the SGIs is really dense, so I'm wondering if it's more
> clean to make it even more dense and rewrite the whole if-statement to:
> 
> 	do {
> 		vgic_populate(vcpu, irq, count++);
> 	} while (irq->source && count < vgic.nr_lr);
> 
> (btw. I believe all these places referencing the nr_lr in the vgic_cpu
> struct could use the global state structure instead).

Good point. We should convert all the places where this is easily doable
already.

> 
>> +
>> +next:
>> +		spin_unlock(&irq->irq_lock);
>> +
>> +		if (count == vcpu->arch.vgic_cpu.nr_lr)
>> +			break;
>> +	}
>> +
>> +	vcpu->arch.vgic_cpu.used_lrs = count;
>> +
>> +	/* Nuke remaining LRs */
>> +	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
>> +		vgic_populate_lr(vcpu, NULL, count);
> 
> should we not change this to adhere to the optimizations Marc
> implemented for the current VGIC (i.e. clear the LRs on sync+init, and
> only write what you need here)?

Those optimizations were not in the branch I based this series on.
I will take a look with the new series being based on 4.6-rc (added
live_lrs already).

Cheers,
Andre.

BTW: Thanks for the thorough review. I agree and will change all your
comments I didn't explicitly replied on.

> 
>> +}
>> +
>> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>> +{
>> +	vgic_process_maintenance_interrupt(vcpu);
>> +	vgic_fold_lr_state(vcpu);
>> +	vgic_prune_ap_list(vcpu);
>> +}
>> +
>> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>> +{
>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +	vgic_populate_lrs(vcpu);
>> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index b2faf00..95ef3cf 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -21,5 +21,9 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>>  
>>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>>  
>>  #endif
>> -- 
>> 2.7.3
>>
> 
> Thanks,
> -Christoffer
> 

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

* Re: [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-04-05 13:34       ` Andre Przywara
@ 2016-04-05 20:10         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-05 20:10 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 29/03/16 14:09, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
> >> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>
> >> Add a new header file for the new and improved GIC implementation.
> >> The big change is that we now have a struct vgic_irq per IRQ instead
> >> of spreading all the information over various bitmaps.
> >>
> >> We include this new header conditionally from within the old header
> >> file for the time being to avoid touching all the users.
> >>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  include/kvm/arm_vgic.h  |   5 ++
> >>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 203 insertions(+)
> >>  create mode 100644 include/kvm/vgic/vgic.h
> >>
> >> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> >> index 7656a46..db289a2 100644
> >> --- a/include/kvm/arm_vgic.h
> >> +++ b/include/kvm/arm_vgic.h
> >> @@ -19,6 +19,10 @@
> >>  #ifndef __ASM_ARM_KVM_VGIC_H
> >>  #define __ASM_ARM_KVM_VGIC_H
> >>  
> >> +#ifdef CONFIG_KVM_NEW_VGIC
> >> +#include <kvm/vgic/vgic.h>
> >> +#else
> >> +
> >>  #include <linux/kernel.h>
> >>  #include <linux/kvm.h>
> >>  #include <linux/irqreturn.h>
> >> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
> >>  }
> >>  #endif
> >>  
> >> +#endif	/* old VGIC include */
> >>  #endif
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> new file mode 100644
> >> index 0000000..659f8b1
> >> --- /dev/null
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -0,0 +1,198 @@
> >> +/*
> >> + * Copyright (C) 2015, 2016 ARM Ltd.
> >> + *
> >> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
> >> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> >> +
> >> +#include <linux/kernel.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/irqreturn.h>
> >> +#include <linux/spinlock.h>
> >> +#include <linux/types.h>
> >> +#include <kvm/iodev.h>
> >> +
> >> +#define VGIC_V3_MAX_CPUS	255
> >> +#define VGIC_V2_MAX_CPUS	8
> >> +#define VGIC_NR_IRQS_LEGACY     256
> >> +#define VGIC_NR_SGIS		16
> >> +#define VGIC_NR_PPIS		16
> >> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> >> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> >> +#define VGIC_MAX_SPI		1019
> >> +#define VGIC_MAX_RESERVED	1023
> >> +#define VGIC_MIN_LPI		8192
> >> +
> >> +enum vgic_type {
> >> +	VGIC_V2,		/* Good ol' GICv2 */
> >> +	VGIC_V3,		/* New fancy GICv3 */
> >> +};
> >> +
> >> +/* same for all guests, as depending only on the _host's_ GIC model */
> >> +struct vgic_global {
> >> +	/* type of the host GIC */
> >> +	enum vgic_type		type;
> >> +
> >> +	/* Physical address of vgic virtual cpu interface */
> >> +	phys_addr_t		vcpu_base;
> >> +
> >> +	/* virtual control interface mapping */
> >> +	void __iomem		*vctrl_base;
> >> +
> >> +	/* Number of implemented list registers */
> >> +	int			nr_lr;
> >> +
> >> +	/* Maintenance IRQ number */
> >> +	unsigned int		maint_irq;
> >> +
> >> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> >> +	int			max_gic_vcpus;
> >> +
> >> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
> >> +	bool			can_emulate_gicv2;
> >> +};
> >> +
> >> +extern struct vgic_global kvm_vgic_global_state;
> >> +
> >> +#define VGIC_V2_MAX_LRS		(1 << 6)
> >> +#define VGIC_V3_MAX_LRS		16
> >> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
> >> +
> >> +enum vgic_irq_config {
> >> +	VGIC_CONFIG_EDGE = 0,
> >> +	VGIC_CONFIG_LEVEL
> >> +};
> >> +
> >> +struct vgic_irq {
> >> +	spinlock_t irq_lock;		/* Protects the content of the struct */
> >> +	struct list_head ap_list;
> >> +
> >> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
> >> +					 * SPIs and LPIs: The VCPU whose ap_list
> >> +					 * on which this is queued.
> >> +					 */
> >> +
> >> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
> >> +					 * be send to, as a result of the
> >> +					 * targets reg (v2) or the
> >> +					 * affinity reg (v3).
> >> +					 */
> >> +
> >> +	u32 intid;			/* Guest visible INTID */
> >> +	bool pending;
> >> +	bool line_level;		/* Level only */
> >> +	bool soft_pending;		/* Level only */
> >> +	bool active;			/* not used for LPIs */
> >> +	bool enabled;
> >> +	bool hw;			/* Tied to HW IRQ */
> >> +	u32 hwintid;			/* HW INTID number */
> >> +	union {
> >> +		u8 targets;			/* GICv2 target VCPUs mask */
> >> +		u32 mpidr;			/* GICv3 target VCPU */
> >> +	};
> >> +	u8 source;			/* GICv2 SGIs only */
> >> +	u8 priority;
> >> +	enum vgic_irq_config config;	/* Level or edge */
> >> +};
> >> +
> >> +struct vgic_dist {
> >> +	bool			in_kernel;
> >> +	bool			ready;
> >> +
> >> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> >> +	u32			vgic_model;
> >> +
> >> +	int			nr_spis;
> >> +
> >> +	/* TODO: Consider moving to global state */
> >> +	/* Virtual control interface mapping */
> >> +	void __iomem		*vctrl_base;
> >> +
> >> +	/* base addresses in guest physical address space: */
> >> +	gpa_t			vgic_dist_base;		/* distributor */
> >> +	union {
> >> +		/* either a GICv2 CPU interface */
> >> +		gpa_t			vgic_cpu_base;
> >> +		/* or a number of GICv3 redistributor regions */
> >> +		gpa_t			vgic_redist_base;
> >> +	};
> >> +
> >> +	/* distributor enabled */
> >> +	u32			enabled;
> >> +
> >> +	struct vgic_irq		*spis;
> >> +};
> >> +
> >> +struct vgic_v2_cpu_if {
> >> +	u32		vgic_hcr;
> >> +	u32		vgic_vmcr;
> >> +	u32		vgic_misr;	/* Saved only */
> >> +	u64		vgic_eisr;	/* Saved only */
> >> +	u64		vgic_elrsr;	/* Saved only */
> >> +	u32		vgic_apr;
> >> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
> >> +};
> >> +
> >> +struct vgic_v3_cpu_if {
> >> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> >> +	u32		vgic_hcr;
> >> +	u32		vgic_vmcr;
> >> +	u32		vgic_sre;	/* Restored only, change ignored */
> >> +	u32		vgic_misr;	/* Saved only */
> >> +	u32		vgic_eisr;	/* Saved only */
> >> +	u32		vgic_elrsr;	/* Saved only */
> >> +	u32		vgic_ap0r[4];
> >> +	u32		vgic_ap1r[4];
> >> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
> >> +#endif
> >> +};
> >> +
> >> +struct vgic_cpu {
> >> +	/* CPU vif control registers for world switch */
> >> +	union {
> >> +		struct vgic_v2_cpu_if	vgic_v2;
> >> +		struct vgic_v3_cpu_if	vgic_v3;
> >> +	};
> >> +
> >> +	/* TODO: Move nr_lr to a global state */
> > 
> > what is our current plan and status about this TODO?
> 
> The point is that the current HYP code is accessing this field. We do
> have this field in the current "global" struct vgic_params there as
> well, but this struct is (more or less) private to vgic-v2.c, so not
> easily accessible from virt/kvm/arm/hyp/*.c.
> So I suggest we keep this in here for the time being and eventually
> remove it (and rework the save/restore code) once we get rid of the old
> VGIC code.
> 
Hmmm, I haven't tried it, but I don't understand why moving it now is
difficult.  I'd really like to avoid having a bunch of todo's lingering
around and having duplicated state in the new code.

I think I noticed a number of places in this patch series which refers
tot he vgic_cpu->nr_lr instead of the global place already...

-Christoffer

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

* [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-04-05 20:10         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-05 20:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 29/03/16 14:09, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
> >> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>
> >> Add a new header file for the new and improved GIC implementation.
> >> The big change is that we now have a struct vgic_irq per IRQ instead
> >> of spreading all the information over various bitmaps.
> >>
> >> We include this new header conditionally from within the old header
> >> file for the time being to avoid touching all the users.
> >>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  include/kvm/arm_vgic.h  |   5 ++
> >>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 203 insertions(+)
> >>  create mode 100644 include/kvm/vgic/vgic.h
> >>
> >> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> >> index 7656a46..db289a2 100644
> >> --- a/include/kvm/arm_vgic.h
> >> +++ b/include/kvm/arm_vgic.h
> >> @@ -19,6 +19,10 @@
> >>  #ifndef __ASM_ARM_KVM_VGIC_H
> >>  #define __ASM_ARM_KVM_VGIC_H
> >>  
> >> +#ifdef CONFIG_KVM_NEW_VGIC
> >> +#include <kvm/vgic/vgic.h>
> >> +#else
> >> +
> >>  #include <linux/kernel.h>
> >>  #include <linux/kvm.h>
> >>  #include <linux/irqreturn.h>
> >> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
> >>  }
> >>  #endif
> >>  
> >> +#endif	/* old VGIC include */
> >>  #endif
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> new file mode 100644
> >> index 0000000..659f8b1
> >> --- /dev/null
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -0,0 +1,198 @@
> >> +/*
> >> + * Copyright (C) 2015, 2016 ARM Ltd.
> >> + *
> >> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
> >> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> >> +
> >> +#include <linux/kernel.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/irqreturn.h>
> >> +#include <linux/spinlock.h>
> >> +#include <linux/types.h>
> >> +#include <kvm/iodev.h>
> >> +
> >> +#define VGIC_V3_MAX_CPUS	255
> >> +#define VGIC_V2_MAX_CPUS	8
> >> +#define VGIC_NR_IRQS_LEGACY     256
> >> +#define VGIC_NR_SGIS		16
> >> +#define VGIC_NR_PPIS		16
> >> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> >> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> >> +#define VGIC_MAX_SPI		1019
> >> +#define VGIC_MAX_RESERVED	1023
> >> +#define VGIC_MIN_LPI		8192
> >> +
> >> +enum vgic_type {
> >> +	VGIC_V2,		/* Good ol' GICv2 */
> >> +	VGIC_V3,		/* New fancy GICv3 */
> >> +};
> >> +
> >> +/* same for all guests, as depending only on the _host's_ GIC model */
> >> +struct vgic_global {
> >> +	/* type of the host GIC */
> >> +	enum vgic_type		type;
> >> +
> >> +	/* Physical address of vgic virtual cpu interface */
> >> +	phys_addr_t		vcpu_base;
> >> +
> >> +	/* virtual control interface mapping */
> >> +	void __iomem		*vctrl_base;
> >> +
> >> +	/* Number of implemented list registers */
> >> +	int			nr_lr;
> >> +
> >> +	/* Maintenance IRQ number */
> >> +	unsigned int		maint_irq;
> >> +
> >> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> >> +	int			max_gic_vcpus;
> >> +
> >> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
> >> +	bool			can_emulate_gicv2;
> >> +};
> >> +
> >> +extern struct vgic_global kvm_vgic_global_state;
> >> +
> >> +#define VGIC_V2_MAX_LRS		(1 << 6)
> >> +#define VGIC_V3_MAX_LRS		16
> >> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
> >> +
> >> +enum vgic_irq_config {
> >> +	VGIC_CONFIG_EDGE = 0,
> >> +	VGIC_CONFIG_LEVEL
> >> +};
> >> +
> >> +struct vgic_irq {
> >> +	spinlock_t irq_lock;		/* Protects the content of the struct */
> >> +	struct list_head ap_list;
> >> +
> >> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
> >> +					 * SPIs and LPIs: The VCPU whose ap_list
> >> +					 * on which this is queued.
> >> +					 */
> >> +
> >> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
> >> +					 * be send to, as a result of the
> >> +					 * targets reg (v2) or the
> >> +					 * affinity reg (v3).
> >> +					 */
> >> +
> >> +	u32 intid;			/* Guest visible INTID */
> >> +	bool pending;
> >> +	bool line_level;		/* Level only */
> >> +	bool soft_pending;		/* Level only */
> >> +	bool active;			/* not used for LPIs */
> >> +	bool enabled;
> >> +	bool hw;			/* Tied to HW IRQ */
> >> +	u32 hwintid;			/* HW INTID number */
> >> +	union {
> >> +		u8 targets;			/* GICv2 target VCPUs mask */
> >> +		u32 mpidr;			/* GICv3 target VCPU */
> >> +	};
> >> +	u8 source;			/* GICv2 SGIs only */
> >> +	u8 priority;
> >> +	enum vgic_irq_config config;	/* Level or edge */
> >> +};
> >> +
> >> +struct vgic_dist {
> >> +	bool			in_kernel;
> >> +	bool			ready;
> >> +
> >> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> >> +	u32			vgic_model;
> >> +
> >> +	int			nr_spis;
> >> +
> >> +	/* TODO: Consider moving to global state */
> >> +	/* Virtual control interface mapping */
> >> +	void __iomem		*vctrl_base;
> >> +
> >> +	/* base addresses in guest physical address space: */
> >> +	gpa_t			vgic_dist_base;		/* distributor */
> >> +	union {
> >> +		/* either a GICv2 CPU interface */
> >> +		gpa_t			vgic_cpu_base;
> >> +		/* or a number of GICv3 redistributor regions */
> >> +		gpa_t			vgic_redist_base;
> >> +	};
> >> +
> >> +	/* distributor enabled */
> >> +	u32			enabled;
> >> +
> >> +	struct vgic_irq		*spis;
> >> +};
> >> +
> >> +struct vgic_v2_cpu_if {
> >> +	u32		vgic_hcr;
> >> +	u32		vgic_vmcr;
> >> +	u32		vgic_misr;	/* Saved only */
> >> +	u64		vgic_eisr;	/* Saved only */
> >> +	u64		vgic_elrsr;	/* Saved only */
> >> +	u32		vgic_apr;
> >> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
> >> +};
> >> +
> >> +struct vgic_v3_cpu_if {
> >> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> >> +	u32		vgic_hcr;
> >> +	u32		vgic_vmcr;
> >> +	u32		vgic_sre;	/* Restored only, change ignored */
> >> +	u32		vgic_misr;	/* Saved only */
> >> +	u32		vgic_eisr;	/* Saved only */
> >> +	u32		vgic_elrsr;	/* Saved only */
> >> +	u32		vgic_ap0r[4];
> >> +	u32		vgic_ap1r[4];
> >> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
> >> +#endif
> >> +};
> >> +
> >> +struct vgic_cpu {
> >> +	/* CPU vif control registers for world switch */
> >> +	union {
> >> +		struct vgic_v2_cpu_if	vgic_v2;
> >> +		struct vgic_v3_cpu_if	vgic_v3;
> >> +	};
> >> +
> >> +	/* TODO: Move nr_lr to a global state */
> > 
> > what is our current plan and status about this TODO?
> 
> The point is that the current HYP code is accessing this field. We do
> have this field in the current "global" struct vgic_params there as
> well, but this struct is (more or less) private to vgic-v2.c, so not
> easily accessible from virt/kvm/arm/hyp/*.c.
> So I suggest we keep this in here for the time being and eventually
> remove it (and rework the save/restore code) once we get rid of the old
> VGIC code.
> 
Hmmm, I haven't tried it, but I don't understand why moving it now is
difficult.  I'd really like to avoid having a bunch of todo's lingering
around and having duplicated state in the new code.

I think I noticed a number of places in this patch series which refers
tot he vgic_cpu->nr_lr instead of the global place already...

-Christoffer

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

* Re: [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-04-05 20:10         ` Christoffer Dall
@ 2016-04-06 13:57           ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-06 13:57 UTC (permalink / raw)
  To: Andre Przywara, G; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Tue, Apr 05, 2016 at 10:10:09PM +0200, Christoffer Dall wrote:
> On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
> > Hi,
> > 
> > On 29/03/16 14:09, Christoffer Dall wrote:
> > > On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
> > >> From: Christoffer Dall <christoffer.dall@linaro.org>
> > >>
> > >> Add a new header file for the new and improved GIC implementation.
> > >> The big change is that we now have a struct vgic_irq per IRQ instead
> > >> of spreading all the information over various bitmaps.
> > >>
> > >> We include this new header conditionally from within the old header
> > >> file for the time being to avoid touching all the users.
> > >>
> > >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > >> ---
> > >>  include/kvm/arm_vgic.h  |   5 ++
> > >>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
> > >>  2 files changed, 203 insertions(+)
> > >>  create mode 100644 include/kvm/vgic/vgic.h
> > >>
> > >> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> > >> index 7656a46..db289a2 100644
> > >> --- a/include/kvm/arm_vgic.h
> > >> +++ b/include/kvm/arm_vgic.h
> > >> @@ -19,6 +19,10 @@
> > >>  #ifndef __ASM_ARM_KVM_VGIC_H
> > >>  #define __ASM_ARM_KVM_VGIC_H
> > >>  
> > >> +#ifdef CONFIG_KVM_NEW_VGIC
> > >> +#include <kvm/vgic/vgic.h>
> > >> +#else
> > >> +
> > >>  #include <linux/kernel.h>
> > >>  #include <linux/kvm.h>
> > >>  #include <linux/irqreturn.h>
> > >> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
> > >>  }
> > >>  #endif
> > >>  
> > >> +#endif	/* old VGIC include */
> > >>  #endif
> > >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> > >> new file mode 100644
> > >> index 0000000..659f8b1
> > >> --- /dev/null
> > >> +++ b/include/kvm/vgic/vgic.h
> > >> @@ -0,0 +1,198 @@
> > >> +/*
> > >> + * Copyright (C) 2015, 2016 ARM Ltd.
> > >> + *
> > >> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
> > >> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> > >> +
> > >> +#include <linux/kernel.h>
> > >> +#include <linux/kvm.h>
> > >> +#include <linux/irqreturn.h>
> > >> +#include <linux/spinlock.h>
> > >> +#include <linux/types.h>
> > >> +#include <kvm/iodev.h>
> > >> +
> > >> +#define VGIC_V3_MAX_CPUS	255
> > >> +#define VGIC_V2_MAX_CPUS	8
> > >> +#define VGIC_NR_IRQS_LEGACY     256
> > >> +#define VGIC_NR_SGIS		16
> > >> +#define VGIC_NR_PPIS		16
> > >> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> > >> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> > >> +#define VGIC_MAX_SPI		1019
> > >> +#define VGIC_MAX_RESERVED	1023
> > >> +#define VGIC_MIN_LPI		8192
> > >> +
> > >> +enum vgic_type {
> > >> +	VGIC_V2,		/* Good ol' GICv2 */
> > >> +	VGIC_V3,		/* New fancy GICv3 */
> > >> +};
> > >> +
> > >> +/* same for all guests, as depending only on the _host's_ GIC model */
> > >> +struct vgic_global {
> > >> +	/* type of the host GIC */
> > >> +	enum vgic_type		type;
> > >> +
> > >> +	/* Physical address of vgic virtual cpu interface */
> > >> +	phys_addr_t		vcpu_base;
> > >> +
> > >> +	/* virtual control interface mapping */
> > >> +	void __iomem		*vctrl_base;
> > >> +
> > >> +	/* Number of implemented list registers */
> > >> +	int			nr_lr;
> > >> +
> > >> +	/* Maintenance IRQ number */
> > >> +	unsigned int		maint_irq;
> > >> +
> > >> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> > >> +	int			max_gic_vcpus;
> > >> +
> > >> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
> > >> +	bool			can_emulate_gicv2;
> > >> +};
> > >> +
> > >> +extern struct vgic_global kvm_vgic_global_state;
> > >> +
> > >> +#define VGIC_V2_MAX_LRS		(1 << 6)
> > >> +#define VGIC_V3_MAX_LRS		16
> > >> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
> > >> +
> > >> +enum vgic_irq_config {
> > >> +	VGIC_CONFIG_EDGE = 0,
> > >> +	VGIC_CONFIG_LEVEL
> > >> +};
> > >> +
> > >> +struct vgic_irq {
> > >> +	spinlock_t irq_lock;		/* Protects the content of the struct */
> > >> +	struct list_head ap_list;
> > >> +
> > >> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
> > >> +					 * SPIs and LPIs: The VCPU whose ap_list
> > >> +					 * on which this is queued.
> > >> +					 */
> > >> +
> > >> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
> > >> +					 * be send to, as a result of the
> > >> +					 * targets reg (v2) or the
> > >> +					 * affinity reg (v3).
> > >> +					 */
> > >> +
> > >> +	u32 intid;			/* Guest visible INTID */
> > >> +	bool pending;
> > >> +	bool line_level;		/* Level only */
> > >> +	bool soft_pending;		/* Level only */
> > >> +	bool active;			/* not used for LPIs */
> > >> +	bool enabled;
> > >> +	bool hw;			/* Tied to HW IRQ */
> > >> +	u32 hwintid;			/* HW INTID number */
> > >> +	union {
> > >> +		u8 targets;			/* GICv2 target VCPUs mask */
> > >> +		u32 mpidr;			/* GICv3 target VCPU */
> > >> +	};
> > >> +	u8 source;			/* GICv2 SGIs only */
> > >> +	u8 priority;
> > >> +	enum vgic_irq_config config;	/* Level or edge */
> > >> +};
> > >> +
> > >> +struct vgic_dist {
> > >> +	bool			in_kernel;
> > >> +	bool			ready;
> > >> +
> > >> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> > >> +	u32			vgic_model;
> > >> +
> > >> +	int			nr_spis;
> > >> +
> > >> +	/* TODO: Consider moving to global state */
> > >> +	/* Virtual control interface mapping */
> > >> +	void __iomem		*vctrl_base;
> > >> +
> > >> +	/* base addresses in guest physical address space: */
> > >> +	gpa_t			vgic_dist_base;		/* distributor */
> > >> +	union {
> > >> +		/* either a GICv2 CPU interface */
> > >> +		gpa_t			vgic_cpu_base;
> > >> +		/* or a number of GICv3 redistributor regions */
> > >> +		gpa_t			vgic_redist_base;
> > >> +	};
> > >> +
> > >> +	/* distributor enabled */
> > >> +	u32			enabled;
> > >> +
> > >> +	struct vgic_irq		*spis;
> > >> +};
> > >> +
> > >> +struct vgic_v2_cpu_if {
> > >> +	u32		vgic_hcr;
> > >> +	u32		vgic_vmcr;
> > >> +	u32		vgic_misr;	/* Saved only */
> > >> +	u64		vgic_eisr;	/* Saved only */
> > >> +	u64		vgic_elrsr;	/* Saved only */
> > >> +	u32		vgic_apr;
> > >> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
> > >> +};
> > >> +
> > >> +struct vgic_v3_cpu_if {
> > >> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> > >> +	u32		vgic_hcr;
> > >> +	u32		vgic_vmcr;
> > >> +	u32		vgic_sre;	/* Restored only, change ignored */
> > >> +	u32		vgic_misr;	/* Saved only */
> > >> +	u32		vgic_eisr;	/* Saved only */
> > >> +	u32		vgic_elrsr;	/* Saved only */
> > >> +	u32		vgic_ap0r[4];
> > >> +	u32		vgic_ap1r[4];
> > >> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
> > >> +#endif
> > >> +};
> > >> +
> > >> +struct vgic_cpu {
> > >> +	/* CPU vif control registers for world switch */
> > >> +	union {
> > >> +		struct vgic_v2_cpu_if	vgic_v2;
> > >> +		struct vgic_v3_cpu_if	vgic_v3;
> > >> +	};
> > >> +
> > >> +	/* TODO: Move nr_lr to a global state */
> > > 
> > > what is our current plan and status about this TODO?
> > 
> > The point is that the current HYP code is accessing this field. We do
> > have this field in the current "global" struct vgic_params there as
> > well, but this struct is (more or less) private to vgic-v2.c, so not
> > easily accessible from virt/kvm/arm/hyp/*.c.
> > So I suggest we keep this in here for the time being and eventually
> > remove it (and rework the save/restore code) once we get rid of the old
> > VGIC code.
> > 
> Hmmm, I haven't tried it, but I don't understand why moving it now is
> difficult.  I'd really like to avoid having a bunch of todo's lingering
> around and having duplicated state in the new code.
> 
> I think I noticed a number of places in this patch series which refers
> tot he vgic_cpu->nr_lr instead of the global place already...
> 
So I wrote a patch for this and it doesn't really look that bad.  I'll
send it as part of a little prerequisite series later.

-Christoffer



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

* [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-04-06 13:57           ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-06 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 05, 2016 at 10:10:09PM +0200, Christoffer Dall wrote:
> On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
> > Hi,
> > 
> > On 29/03/16 14:09, Christoffer Dall wrote:
> > > On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
> > >> From: Christoffer Dall <christoffer.dall@linaro.org>
> > >>
> > >> Add a new header file for the new and improved GIC implementation.
> > >> The big change is that we now have a struct vgic_irq per IRQ instead
> > >> of spreading all the information over various bitmaps.
> > >>
> > >> We include this new header conditionally from within the old header
> > >> file for the time being to avoid touching all the users.
> > >>
> > >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > >> ---
> > >>  include/kvm/arm_vgic.h  |   5 ++
> > >>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
> > >>  2 files changed, 203 insertions(+)
> > >>  create mode 100644 include/kvm/vgic/vgic.h
> > >>
> > >> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> > >> index 7656a46..db289a2 100644
> > >> --- a/include/kvm/arm_vgic.h
> > >> +++ b/include/kvm/arm_vgic.h
> > >> @@ -19,6 +19,10 @@
> > >>  #ifndef __ASM_ARM_KVM_VGIC_H
> > >>  #define __ASM_ARM_KVM_VGIC_H
> > >>  
> > >> +#ifdef CONFIG_KVM_NEW_VGIC
> > >> +#include <kvm/vgic/vgic.h>
> > >> +#else
> > >> +
> > >>  #include <linux/kernel.h>
> > >>  #include <linux/kvm.h>
> > >>  #include <linux/irqreturn.h>
> > >> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
> > >>  }
> > >>  #endif
> > >>  
> > >> +#endif	/* old VGIC include */
> > >>  #endif
> > >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> > >> new file mode 100644
> > >> index 0000000..659f8b1
> > >> --- /dev/null
> > >> +++ b/include/kvm/vgic/vgic.h
> > >> @@ -0,0 +1,198 @@
> > >> +/*
> > >> + * Copyright (C) 2015, 2016 ARM Ltd.
> > >> + *
> > >> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
> > >> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> > >> +
> > >> +#include <linux/kernel.h>
> > >> +#include <linux/kvm.h>
> > >> +#include <linux/irqreturn.h>
> > >> +#include <linux/spinlock.h>
> > >> +#include <linux/types.h>
> > >> +#include <kvm/iodev.h>
> > >> +
> > >> +#define VGIC_V3_MAX_CPUS	255
> > >> +#define VGIC_V2_MAX_CPUS	8
> > >> +#define VGIC_NR_IRQS_LEGACY     256
> > >> +#define VGIC_NR_SGIS		16
> > >> +#define VGIC_NR_PPIS		16
> > >> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> > >> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> > >> +#define VGIC_MAX_SPI		1019
> > >> +#define VGIC_MAX_RESERVED	1023
> > >> +#define VGIC_MIN_LPI		8192
> > >> +
> > >> +enum vgic_type {
> > >> +	VGIC_V2,		/* Good ol' GICv2 */
> > >> +	VGIC_V3,		/* New fancy GICv3 */
> > >> +};
> > >> +
> > >> +/* same for all guests, as depending only on the _host's_ GIC model */
> > >> +struct vgic_global {
> > >> +	/* type of the host GIC */
> > >> +	enum vgic_type		type;
> > >> +
> > >> +	/* Physical address of vgic virtual cpu interface */
> > >> +	phys_addr_t		vcpu_base;
> > >> +
> > >> +	/* virtual control interface mapping */
> > >> +	void __iomem		*vctrl_base;
> > >> +
> > >> +	/* Number of implemented list registers */
> > >> +	int			nr_lr;
> > >> +
> > >> +	/* Maintenance IRQ number */
> > >> +	unsigned int		maint_irq;
> > >> +
> > >> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> > >> +	int			max_gic_vcpus;
> > >> +
> > >> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
> > >> +	bool			can_emulate_gicv2;
> > >> +};
> > >> +
> > >> +extern struct vgic_global kvm_vgic_global_state;
> > >> +
> > >> +#define VGIC_V2_MAX_LRS		(1 << 6)
> > >> +#define VGIC_V3_MAX_LRS		16
> > >> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
> > >> +
> > >> +enum vgic_irq_config {
> > >> +	VGIC_CONFIG_EDGE = 0,
> > >> +	VGIC_CONFIG_LEVEL
> > >> +};
> > >> +
> > >> +struct vgic_irq {
> > >> +	spinlock_t irq_lock;		/* Protects the content of the struct */
> > >> +	struct list_head ap_list;
> > >> +
> > >> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
> > >> +					 * SPIs and LPIs: The VCPU whose ap_list
> > >> +					 * on which this is queued.
> > >> +					 */
> > >> +
> > >> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
> > >> +					 * be send to, as a result of the
> > >> +					 * targets reg (v2) or the
> > >> +					 * affinity reg (v3).
> > >> +					 */
> > >> +
> > >> +	u32 intid;			/* Guest visible INTID */
> > >> +	bool pending;
> > >> +	bool line_level;		/* Level only */
> > >> +	bool soft_pending;		/* Level only */
> > >> +	bool active;			/* not used for LPIs */
> > >> +	bool enabled;
> > >> +	bool hw;			/* Tied to HW IRQ */
> > >> +	u32 hwintid;			/* HW INTID number */
> > >> +	union {
> > >> +		u8 targets;			/* GICv2 target VCPUs mask */
> > >> +		u32 mpidr;			/* GICv3 target VCPU */
> > >> +	};
> > >> +	u8 source;			/* GICv2 SGIs only */
> > >> +	u8 priority;
> > >> +	enum vgic_irq_config config;	/* Level or edge */
> > >> +};
> > >> +
> > >> +struct vgic_dist {
> > >> +	bool			in_kernel;
> > >> +	bool			ready;
> > >> +
> > >> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> > >> +	u32			vgic_model;
> > >> +
> > >> +	int			nr_spis;
> > >> +
> > >> +	/* TODO: Consider moving to global state */
> > >> +	/* Virtual control interface mapping */
> > >> +	void __iomem		*vctrl_base;
> > >> +
> > >> +	/* base addresses in guest physical address space: */
> > >> +	gpa_t			vgic_dist_base;		/* distributor */
> > >> +	union {
> > >> +		/* either a GICv2 CPU interface */
> > >> +		gpa_t			vgic_cpu_base;
> > >> +		/* or a number of GICv3 redistributor regions */
> > >> +		gpa_t			vgic_redist_base;
> > >> +	};
> > >> +
> > >> +	/* distributor enabled */
> > >> +	u32			enabled;
> > >> +
> > >> +	struct vgic_irq		*spis;
> > >> +};
> > >> +
> > >> +struct vgic_v2_cpu_if {
> > >> +	u32		vgic_hcr;
> > >> +	u32		vgic_vmcr;
> > >> +	u32		vgic_misr;	/* Saved only */
> > >> +	u64		vgic_eisr;	/* Saved only */
> > >> +	u64		vgic_elrsr;	/* Saved only */
> > >> +	u32		vgic_apr;
> > >> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
> > >> +};
> > >> +
> > >> +struct vgic_v3_cpu_if {
> > >> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> > >> +	u32		vgic_hcr;
> > >> +	u32		vgic_vmcr;
> > >> +	u32		vgic_sre;	/* Restored only, change ignored */
> > >> +	u32		vgic_misr;	/* Saved only */
> > >> +	u32		vgic_eisr;	/* Saved only */
> > >> +	u32		vgic_elrsr;	/* Saved only */
> > >> +	u32		vgic_ap0r[4];
> > >> +	u32		vgic_ap1r[4];
> > >> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
> > >> +#endif
> > >> +};
> > >> +
> > >> +struct vgic_cpu {
> > >> +	/* CPU vif control registers for world switch */
> > >> +	union {
> > >> +		struct vgic_v2_cpu_if	vgic_v2;
> > >> +		struct vgic_v3_cpu_if	vgic_v3;
> > >> +	};
> > >> +
> > >> +	/* TODO: Move nr_lr to a global state */
> > > 
> > > what is our current plan and status about this TODO?
> > 
> > The point is that the current HYP code is accessing this field. We do
> > have this field in the current "global" struct vgic_params there as
> > well, but this struct is (more or less) private to vgic-v2.c, so not
> > easily accessible from virt/kvm/arm/hyp/*.c.
> > So I suggest we keep this in here for the time being and eventually
> > remove it (and rework the save/restore code) once we get rid of the old
> > VGIC code.
> > 
> Hmmm, I haven't tried it, but I don't understand why moving it now is
> difficult.  I'd really like to avoid having a bunch of todo's lingering
> around and having duplicated state in the new code.
> 
> I think I noticed a number of places in this patch series which refers
> tot he vgic_cpu->nr_lr instead of the global place already...
> 
So I wrote a patch for this and it doesn't really look that bad.  I'll
send it as part of a little prerequisite series later.

-Christoffer

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

* Re: [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-04-06 13:57           ` Christoffer Dall
@ 2016-04-06 14:09             ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-06 14:09 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm



On 06/04/16 14:57, Christoffer Dall wrote:
> On Tue, Apr 05, 2016 at 10:10:09PM +0200, Christoffer Dall wrote:
>> On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
>>> Hi,
>>>
>>> On 29/03/16 14:09, Christoffer Dall wrote:
>>>> On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
>>>>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>>>>
>>>>> Add a new header file for the new and improved GIC implementation.
>>>>> The big change is that we now have a struct vgic_irq per IRQ instead
>>>>> of spreading all the information over various bitmaps.
>>>>>
>>>>> We include this new header conditionally from within the old header
>>>>> file for the time being to avoid touching all the users.
>>>>>
>>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>> ---
>>>>>  include/kvm/arm_vgic.h  |   5 ++
>>>>>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>  2 files changed, 203 insertions(+)
>>>>>  create mode 100644 include/kvm/vgic/vgic.h
>>>>>
>>>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>>>> index 7656a46..db289a2 100644
>>>>> --- a/include/kvm/arm_vgic.h
>>>>> +++ b/include/kvm/arm_vgic.h
>>>>> @@ -19,6 +19,10 @@
>>>>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>>>>  #define __ASM_ARM_KVM_VGIC_H
>>>>>
>>>>> +#ifdef CONFIG_KVM_NEW_VGIC
>>>>> +#include <kvm/vgic/vgic.h>
>>>>> +#else
>>>>> +
>>>>>  #include <linux/kernel.h>
>>>>>  #include <linux/kvm.h>
>>>>>  #include <linux/irqreturn.h>
>>>>> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>>>>  }
>>>>>  #endif
>>>>>
>>>>> +#endif   /* old VGIC include */
>>>>>  #endif
>>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>>>>> new file mode 100644
>>>>> index 0000000..659f8b1
>>>>> --- /dev/null
>>>>> +++ b/include/kvm/vgic/vgic.h
>>>>> @@ -0,0 +1,198 @@
>>>>> +/*
>>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>>> + *
>>>>> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
>>>>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>>>>> +
>>>>> +#include <linux/kernel.h>
>>>>> +#include <linux/kvm.h>
>>>>> +#include <linux/irqreturn.h>
>>>>> +#include <linux/spinlock.h>
>>>>> +#include <linux/types.h>
>>>>> +#include <kvm/iodev.h>
>>>>> +
>>>>> +#define VGIC_V3_MAX_CPUS 255
>>>>> +#define VGIC_V2_MAX_CPUS 8
>>>>> +#define VGIC_NR_IRQS_LEGACY     256
>>>>> +#define VGIC_NR_SGIS             16
>>>>> +#define VGIC_NR_PPIS             16
>>>>> +#define VGIC_NR_PRIVATE_IRQS     (VGIC_NR_SGIS + VGIC_NR_PPIS)
>>>>> +#define VGIC_MAX_PRIVATE (VGIC_NR_PRIVATE_IRQS - 1)
>>>>> +#define VGIC_MAX_SPI             1019
>>>>> +#define VGIC_MAX_RESERVED        1023
>>>>> +#define VGIC_MIN_LPI             8192
>>>>> +
>>>>> +enum vgic_type {
>>>>> + VGIC_V2,                /* Good ol' GICv2 */
>>>>> + VGIC_V3,                /* New fancy GICv3 */
>>>>> +};
>>>>> +
>>>>> +/* same for all guests, as depending only on the _host's_ GIC model */
>>>>> +struct vgic_global {
>>>>> + /* type of the host GIC */
>>>>> + enum vgic_type          type;
>>>>> +
>>>>> + /* Physical address of vgic virtual cpu interface */
>>>>> + phys_addr_t             vcpu_base;
>>>>> +
>>>>> + /* virtual control interface mapping */
>>>>> + void __iomem            *vctrl_base;
>>>>> +
>>>>> + /* Number of implemented list registers */
>>>>> + int                     nr_lr;
>>>>> +
>>>>> + /* Maintenance IRQ number */
>>>>> + unsigned int            maint_irq;
>>>>> +
>>>>> + /* maximum number of VCPUs allowed (GICv2 limits us to 8) */
>>>>> + int                     max_gic_vcpus;
>>>>> +
>>>>> + /* Only needed for the legacy KVM_CREATE_IRQCHIP */
>>>>> + bool                    can_emulate_gicv2;
>>>>> +};
>>>>> +
>>>>> +extern struct vgic_global kvm_vgic_global_state;
>>>>> +
>>>>> +#define VGIC_V2_MAX_LRS          (1 << 6)
>>>>> +#define VGIC_V3_MAX_LRS          16
>>>>> +#define VGIC_V3_LR_INDEX(lr)     (VGIC_V3_MAX_LRS - 1 - lr)
>>>>> +
>>>>> +enum vgic_irq_config {
>>>>> + VGIC_CONFIG_EDGE = 0,
>>>>> + VGIC_CONFIG_LEVEL
>>>>> +};
>>>>> +
>>>>> +struct vgic_irq {
>>>>> + spinlock_t irq_lock;            /* Protects the content of the struct */
>>>>> + struct list_head ap_list;
>>>>> +
>>>>> + struct kvm_vcpu *vcpu;          /* SGIs and PPIs: The VCPU
>>>>> +                                  * SPIs and LPIs: The VCPU whose ap_list
>>>>> +                                  * on which this is queued.
>>>>> +                                  */
>>>>> +
>>>>> + struct kvm_vcpu *target_vcpu;   /* The VCPU that this interrupt should
>>>>> +                                  * be send to, as a result of the
>>>>> +                                  * targets reg (v2) or the
>>>>> +                                  * affinity reg (v3).
>>>>> +                                  */
>>>>> +
>>>>> + u32 intid;                      /* Guest visible INTID */
>>>>> + bool pending;
>>>>> + bool line_level;                /* Level only */
>>>>> + bool soft_pending;              /* Level only */
>>>>> + bool active;                    /* not used for LPIs */
>>>>> + bool enabled;
>>>>> + bool hw;                        /* Tied to HW IRQ */
>>>>> + u32 hwintid;                    /* HW INTID number */
>>>>> + union {
>>>>> +         u8 targets;                     /* GICv2 target VCPUs mask */
>>>>> +         u32 mpidr;                      /* GICv3 target VCPU */
>>>>> + };
>>>>> + u8 source;                      /* GICv2 SGIs only */
>>>>> + u8 priority;
>>>>> + enum vgic_irq_config config;    /* Level or edge */
>>>>> +};
>>>>> +
>>>>> +struct vgic_dist {
>>>>> + bool                    in_kernel;
>>>>> + bool                    ready;
>>>>> +
>>>>> + /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>>>>> + u32                     vgic_model;
>>>>> +
>>>>> + int                     nr_spis;
>>>>> +
>>>>> + /* TODO: Consider moving to global state */
>>>>> + /* Virtual control interface mapping */
>>>>> + void __iomem            *vctrl_base;
>>>>> +
>>>>> + /* base addresses in guest physical address space: */
>>>>> + gpa_t                   vgic_dist_base;         /* distributor */
>>>>> + union {
>>>>> +         /* either a GICv2 CPU interface */
>>>>> +         gpa_t                   vgic_cpu_base;
>>>>> +         /* or a number of GICv3 redistributor regions */
>>>>> +         gpa_t                   vgic_redist_base;
>>>>> + };
>>>>> +
>>>>> + /* distributor enabled */
>>>>> + u32                     enabled;
>>>>> +
>>>>> + struct vgic_irq         *spis;
>>>>> +};
>>>>> +
>>>>> +struct vgic_v2_cpu_if {
>>>>> + u32             vgic_hcr;
>>>>> + u32             vgic_vmcr;
>>>>> + u32             vgic_misr;      /* Saved only */
>>>>> + u64             vgic_eisr;      /* Saved only */
>>>>> + u64             vgic_elrsr;     /* Saved only */
>>>>> + u32             vgic_apr;
>>>>> + u32             vgic_lr[VGIC_V2_MAX_LRS];
>>>>> +};
>>>>> +
>>>>> +struct vgic_v3_cpu_if {
>>>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>>>>> + u32             vgic_hcr;
>>>>> + u32             vgic_vmcr;
>>>>> + u32             vgic_sre;       /* Restored only, change ignored */
>>>>> + u32             vgic_misr;      /* Saved only */
>>>>> + u32             vgic_eisr;      /* Saved only */
>>>>> + u32             vgic_elrsr;     /* Saved only */
>>>>> + u32             vgic_ap0r[4];
>>>>> + u32             vgic_ap1r[4];
>>>>> + u64             vgic_lr[VGIC_V3_MAX_LRS];
>>>>> +#endif
>>>>> +};
>>>>> +
>>>>> +struct vgic_cpu {
>>>>> + /* CPU vif control registers for world switch */
>>>>> + union {
>>>>> +         struct vgic_v2_cpu_if   vgic_v2;
>>>>> +         struct vgic_v3_cpu_if   vgic_v3;
>>>>> + };
>>>>> +
>>>>> + /* TODO: Move nr_lr to a global state */
>>>>
>>>> what is our current plan and status about this TODO?
>>>
>>> The point is that the current HYP code is accessing this field. We do
>>> have this field in the current "global" struct vgic_params there as
>>> well, but this struct is (more or less) private to vgic-v2.c, so not
>>> easily accessible from virt/kvm/arm/hyp/*.c.
>>> So I suggest we keep this in here for the time being and eventually
>>> remove it (and rework the save/restore code) once we get rid of the old
>>> VGIC code.
>>>
>> Hmmm, I haven't tried it, but I don't understand why moving it now is
>> difficult.  I'd really like to avoid having a bunch of todo's lingering
>> around and having duplicated state in the new code.
>>
>> I think I noticed a number of places in this patch series which refers
>> tot he vgic_cpu->nr_lr instead of the global place already...
>>
> So I wrote a patch for this and it doesn't really look that bad.  I'll
> send it as part of a little prerequisite series later.

I just fixed it as well - the private new VGIC part is trivial indeed.
But how did you solve the reference to the vgic_cpu.nr_lr in
virt/kvm/arm/hyp/vgic-v2-sr.c? With #ifdef .. #else? Or passing in the
number as in vgic-v3-sr.c?

Cheers,
Andre.
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

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

* [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-04-06 14:09             ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-06 14:09 UTC (permalink / raw)
  To: linux-arm-kernel



On 06/04/16 14:57, Christoffer Dall wrote:
> On Tue, Apr 05, 2016 at 10:10:09PM +0200, Christoffer Dall wrote:
>> On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
>>> Hi,
>>>
>>> On 29/03/16 14:09, Christoffer Dall wrote:
>>>> On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
>>>>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>>>>
>>>>> Add a new header file for the new and improved GIC implementation.
>>>>> The big change is that we now have a struct vgic_irq per IRQ instead
>>>>> of spreading all the information over various bitmaps.
>>>>>
>>>>> We include this new header conditionally from within the old header
>>>>> file for the time being to avoid touching all the users.
>>>>>
>>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>> ---
>>>>>  include/kvm/arm_vgic.h  |   5 ++
>>>>>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>  2 files changed, 203 insertions(+)
>>>>>  create mode 100644 include/kvm/vgic/vgic.h
>>>>>
>>>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>>>> index 7656a46..db289a2 100644
>>>>> --- a/include/kvm/arm_vgic.h
>>>>> +++ b/include/kvm/arm_vgic.h
>>>>> @@ -19,6 +19,10 @@
>>>>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>>>>  #define __ASM_ARM_KVM_VGIC_H
>>>>>
>>>>> +#ifdef CONFIG_KVM_NEW_VGIC
>>>>> +#include <kvm/vgic/vgic.h>
>>>>> +#else
>>>>> +
>>>>>  #include <linux/kernel.h>
>>>>>  #include <linux/kvm.h>
>>>>>  #include <linux/irqreturn.h>
>>>>> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>>>>  }
>>>>>  #endif
>>>>>
>>>>> +#endif   /* old VGIC include */
>>>>>  #endif
>>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>>>>> new file mode 100644
>>>>> index 0000000..659f8b1
>>>>> --- /dev/null
>>>>> +++ b/include/kvm/vgic/vgic.h
>>>>> @@ -0,0 +1,198 @@
>>>>> +/*
>>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>>> + *
>>>>> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
>>>>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>>>>> +
>>>>> +#include <linux/kernel.h>
>>>>> +#include <linux/kvm.h>
>>>>> +#include <linux/irqreturn.h>
>>>>> +#include <linux/spinlock.h>
>>>>> +#include <linux/types.h>
>>>>> +#include <kvm/iodev.h>
>>>>> +
>>>>> +#define VGIC_V3_MAX_CPUS 255
>>>>> +#define VGIC_V2_MAX_CPUS 8
>>>>> +#define VGIC_NR_IRQS_LEGACY     256
>>>>> +#define VGIC_NR_SGIS             16
>>>>> +#define VGIC_NR_PPIS             16
>>>>> +#define VGIC_NR_PRIVATE_IRQS     (VGIC_NR_SGIS + VGIC_NR_PPIS)
>>>>> +#define VGIC_MAX_PRIVATE (VGIC_NR_PRIVATE_IRQS - 1)
>>>>> +#define VGIC_MAX_SPI             1019
>>>>> +#define VGIC_MAX_RESERVED        1023
>>>>> +#define VGIC_MIN_LPI             8192
>>>>> +
>>>>> +enum vgic_type {
>>>>> + VGIC_V2,                /* Good ol' GICv2 */
>>>>> + VGIC_V3,                /* New fancy GICv3 */
>>>>> +};
>>>>> +
>>>>> +/* same for all guests, as depending only on the _host's_ GIC model */
>>>>> +struct vgic_global {
>>>>> + /* type of the host GIC */
>>>>> + enum vgic_type          type;
>>>>> +
>>>>> + /* Physical address of vgic virtual cpu interface */
>>>>> + phys_addr_t             vcpu_base;
>>>>> +
>>>>> + /* virtual control interface mapping */
>>>>> + void __iomem            *vctrl_base;
>>>>> +
>>>>> + /* Number of implemented list registers */
>>>>> + int                     nr_lr;
>>>>> +
>>>>> + /* Maintenance IRQ number */
>>>>> + unsigned int            maint_irq;
>>>>> +
>>>>> + /* maximum number of VCPUs allowed (GICv2 limits us to 8) */
>>>>> + int                     max_gic_vcpus;
>>>>> +
>>>>> + /* Only needed for the legacy KVM_CREATE_IRQCHIP */
>>>>> + bool                    can_emulate_gicv2;
>>>>> +};
>>>>> +
>>>>> +extern struct vgic_global kvm_vgic_global_state;
>>>>> +
>>>>> +#define VGIC_V2_MAX_LRS          (1 << 6)
>>>>> +#define VGIC_V3_MAX_LRS          16
>>>>> +#define VGIC_V3_LR_INDEX(lr)     (VGIC_V3_MAX_LRS - 1 - lr)
>>>>> +
>>>>> +enum vgic_irq_config {
>>>>> + VGIC_CONFIG_EDGE = 0,
>>>>> + VGIC_CONFIG_LEVEL
>>>>> +};
>>>>> +
>>>>> +struct vgic_irq {
>>>>> + spinlock_t irq_lock;            /* Protects the content of the struct */
>>>>> + struct list_head ap_list;
>>>>> +
>>>>> + struct kvm_vcpu *vcpu;          /* SGIs and PPIs: The VCPU
>>>>> +                                  * SPIs and LPIs: The VCPU whose ap_list
>>>>> +                                  * on which this is queued.
>>>>> +                                  */
>>>>> +
>>>>> + struct kvm_vcpu *target_vcpu;   /* The VCPU that this interrupt should
>>>>> +                                  * be send to, as a result of the
>>>>> +                                  * targets reg (v2) or the
>>>>> +                                  * affinity reg (v3).
>>>>> +                                  */
>>>>> +
>>>>> + u32 intid;                      /* Guest visible INTID */
>>>>> + bool pending;
>>>>> + bool line_level;                /* Level only */
>>>>> + bool soft_pending;              /* Level only */
>>>>> + bool active;                    /* not used for LPIs */
>>>>> + bool enabled;
>>>>> + bool hw;                        /* Tied to HW IRQ */
>>>>> + u32 hwintid;                    /* HW INTID number */
>>>>> + union {
>>>>> +         u8 targets;                     /* GICv2 target VCPUs mask */
>>>>> +         u32 mpidr;                      /* GICv3 target VCPU */
>>>>> + };
>>>>> + u8 source;                      /* GICv2 SGIs only */
>>>>> + u8 priority;
>>>>> + enum vgic_irq_config config;    /* Level or edge */
>>>>> +};
>>>>> +
>>>>> +struct vgic_dist {
>>>>> + bool                    in_kernel;
>>>>> + bool                    ready;
>>>>> +
>>>>> + /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>>>>> + u32                     vgic_model;
>>>>> +
>>>>> + int                     nr_spis;
>>>>> +
>>>>> + /* TODO: Consider moving to global state */
>>>>> + /* Virtual control interface mapping */
>>>>> + void __iomem            *vctrl_base;
>>>>> +
>>>>> + /* base addresses in guest physical address space: */
>>>>> + gpa_t                   vgic_dist_base;         /* distributor */
>>>>> + union {
>>>>> +         /* either a GICv2 CPU interface */
>>>>> +         gpa_t                   vgic_cpu_base;
>>>>> +         /* or a number of GICv3 redistributor regions */
>>>>> +         gpa_t                   vgic_redist_base;
>>>>> + };
>>>>> +
>>>>> + /* distributor enabled */
>>>>> + u32                     enabled;
>>>>> +
>>>>> + struct vgic_irq         *spis;
>>>>> +};
>>>>> +
>>>>> +struct vgic_v2_cpu_if {
>>>>> + u32             vgic_hcr;
>>>>> + u32             vgic_vmcr;
>>>>> + u32             vgic_misr;      /* Saved only */
>>>>> + u64             vgic_eisr;      /* Saved only */
>>>>> + u64             vgic_elrsr;     /* Saved only */
>>>>> + u32             vgic_apr;
>>>>> + u32             vgic_lr[VGIC_V2_MAX_LRS];
>>>>> +};
>>>>> +
>>>>> +struct vgic_v3_cpu_if {
>>>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>>>>> + u32             vgic_hcr;
>>>>> + u32             vgic_vmcr;
>>>>> + u32             vgic_sre;       /* Restored only, change ignored */
>>>>> + u32             vgic_misr;      /* Saved only */
>>>>> + u32             vgic_eisr;      /* Saved only */
>>>>> + u32             vgic_elrsr;     /* Saved only */
>>>>> + u32             vgic_ap0r[4];
>>>>> + u32             vgic_ap1r[4];
>>>>> + u64             vgic_lr[VGIC_V3_MAX_LRS];
>>>>> +#endif
>>>>> +};
>>>>> +
>>>>> +struct vgic_cpu {
>>>>> + /* CPU vif control registers for world switch */
>>>>> + union {
>>>>> +         struct vgic_v2_cpu_if   vgic_v2;
>>>>> +         struct vgic_v3_cpu_if   vgic_v3;
>>>>> + };
>>>>> +
>>>>> + /* TODO: Move nr_lr to a global state */
>>>>
>>>> what is our current plan and status about this TODO?
>>>
>>> The point is that the current HYP code is accessing this field. We do
>>> have this field in the current "global" struct vgic_params there as
>>> well, but this struct is (more or less) private to vgic-v2.c, so not
>>> easily accessible from virt/kvm/arm/hyp/*.c.
>>> So I suggest we keep this in here for the time being and eventually
>>> remove it (and rework the save/restore code) once we get rid of the old
>>> VGIC code.
>>>
>> Hmmm, I haven't tried it, but I don't understand why moving it now is
>> difficult.  I'd really like to avoid having a bunch of todo's lingering
>> around and having duplicated state in the new code.
>>
>> I think I noticed a number of places in this patch series which refers
>> tot he vgic_cpu->nr_lr instead of the global place already...
>>
> So I wrote a patch for this and it doesn't really look that bad.  I'll
> send it as part of a little prerequisite series later.

I just fixed it as well - the private new VGIC part is trivial indeed.
But how did you solve the reference to the vgic_cpu.nr_lr in
virt/kvm/arm/hyp/vgic-v2-sr.c? With #ifdef .. #else? Or passing in the
number as in vgic-v3-sr.c?

Cheers,
Andre.
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

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

* Re: [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-04-05 17:28       ` Andre Przywara
@ 2016-04-06 14:23         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-06 14:23 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Tue, Apr 05, 2016 at 06:28:55PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 29/03/16 22:16, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:29AM +0000, Andre Przywara wrote:
> >> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>
> >> Provide a vgic_queue_irq() function which decides whether a given
> >> IRQ needs to be queued to a VCPU's ap_list.
> >> This should be called whenever an IRQ became pending or got enabled,
> > 
> > becomes pending or enabled,
> > 
> >> either as a result of userspace injection, from in-kernel emulated
> >> devices like the architected timer or from MMIO accesses to the
> >> distributor emulation.
> >> Also provides the necessary functions to allow userland to inject an
> >> IRQ to a guest.
> > 
> > Since this is the first code that starts using our locking mechanism, we
> > add some (hopefully) clear documentation of our locking strategy and
> > requirements along with this patch.
> > 
> >> [Andre: refactor out vgic_queue_irq()]
> >>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  include/kvm/vgic/vgic.h  |   3 +
> >>  virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.h |   1 +
> >>  3 files changed, 185 insertions(+)
> >>
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> index 659f8b1..f32b284 100644
> >> --- a/include/kvm/vgic/vgic.h
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -178,6 +178,9 @@ struct vgic_cpu {
> >>  	struct list_head ap_list_head;
> >>  };
> >>  
> >> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> >> +			bool level);
> >> +
> >>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> >>  #define vgic_initialized(k)	(false)
> >>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> >> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> >> index 8e34916..a95aabc 100644
> >> --- a/virt/kvm/arm/vgic/vgic.c
> >> +++ b/virt/kvm/arm/vgic/vgic.c
> >> @@ -19,8 +19,25 @@
> >>  
> >>  #include "vgic.h"
> >>  
> >> +#define CREATE_TRACE_POINTS
> >> +#include "../trace.h"
> >> +
> >>  struct vgic_global kvm_vgic_global_state;
> >>  
> >> +/*
> >> + * Locking order is always:
> >> + *   vgic_cpu->ap_list_lock
> >> + *     vgic_irq->irq_lock
> >> + *
> >> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
> >> + *
> >> + * When taking more than one ap_list_lock at the same time, always take the
> >> + * lowest numbered VCPU's ap_list_lock first, so:
> >> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
> >> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
> >> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
> >> + */
> >> +
> >>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>  			      u32 intid)
> >>  {
> >> @@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
> >>  	return NULL;
> >>  }
> >> +
> >> +/**
> >> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
> >> + *
> >> + * @irq:	The irq to route. Must be already locked.
> 
>                                   ^^^^^^^^^^^^^^^^^^^^^^
> 
> >> + *
> >> + * Based on the current state of the interrupt (enabled, pending,
> >> + * active, vcpu and target_vcpu), compute the next vcpu this should be
> >> + * given to. Return NULL if this shouldn't be injected at all.
> >> + */
> >> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
> >> +{
> >> +	/* If the interrupt is active, it must stay on the current vcpu */
> >> +	if (irq->active)
> >> +		return irq->vcpu;
> > 
> > we are not taking a lock here.  What are the locking expectations?  If
> > the expectarions are that the IRQ is locked when calling this function,
> > can we have a BIG FAT COMMENT saying that then?
> 
> Do you mean really BIG FAT or is the above sufficient? (I guess not).
> I will make it more prominent.

well, maybe it doesn't have to be BIG FAT.  But I did miss the existing
comment.  I think it would be preferred to have a separate paragraph
explaining the locking expectaions, but perhaps I'm just
being stupid.

> 
> > It seems to me that we are somehow expecting irq->active and irq->vcpu
> > to be in sync, but that's not necessarily the case if the IRQ is not
> > locked.
> > 
> >> +
> >> +	/* If enabled and pending, it can migrate to a new one */
> > 
> > I think this comment should be rewritten to:
> > 
> > If the IRQ is not active but enabled and pending, we should direct it to
> > its configured target VCPU.
> > 
> >> +	if (irq->enabled && irq->pending)
> >> +		return irq->target_vcpu;
> >> +
> >> +	/* Otherwise, it is considered idle */
> > 
> > not sure what idle means here, I suggest something like:
> > 
> > If neither active nor pending and enabled, then this IRQ should not be
> > queued to any VCPU.
> > 
> >> +	return NULL;
> >> +}
> >> +
> >> +/*
> >> + * Only valid injection if changing level for level-triggered IRQs or for a
> >> + * rising edge.
> >> + */
> >> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
> >> +{
> >> +	switch (irq->config) {
> >> +	case VGIC_CONFIG_LEVEL:
> >> +		return irq->line_level != level;
> >> +	case VGIC_CONFIG_EDGE:
> >> +		return level;
> >> +	default:
> >> +		BUG();
> > 
> > is the default case there for making the compiler happy or can we just
> > get rid of it?
> 
> Just removing it was fine (for GCC 5.3.0, at least).
> 
> >> +	}
> >> +}
> >> +
> >> +/*
> >> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
> >> + * Do the queuing if necessary, taking the right locks in the right order.
> >> + * Returns true when the IRQ was queued, false otherwise.
> >> + *
> >> + * Needs to be entered with the IRQ lock already held, but will return
> >> + * with all locks dropped.
> >> + */
> >> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)
> > 
> > should we name this vgic_try_queue_irq_locked ?
> 
> Mmh, since it (re-)tries quite hard I am not sure _try_ would be
> misleading. Basically it queues the IRQ whenever possible and/or
> sensible. Having _unlock in it like you suggested in another reply makes
> more sense, I think.

agreed

> 
> >> +{
> >> +	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);
> > 
> > should we have something like BUG_ON(!spin_is_locked(irq->irq_lock));
> > here?
> > 
> > Not sure if there's some bug checking here which is only emitted if a
> > user select CONFIG_CHECK_SOME_LOCKING_THINGS that we could use...?
> 
> There is CONFIG_DEBUG_SPINLOCK, but I couldn't find some conditional
> debug macro suitable for the purpose. I defined one now for the file
> only (since we have quite some users here).
> 
> >> +
> >> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
> >> +		/*
> >> +		 * If this IRQ is already on a VCPU's ap_list, then it
> >> +		 * cannot be moved or modified and there is no more work for
> >> +		 * us to do.
> >> +		 *
> >> +		 * Otherwise, if the irq is not pending and enabled, it does
> >> +		 * not need to be inserted into an ap_list and there is also
> >> +		 * no more work for us to do.
> >> +		 */
> > 
> > is the !vcpu check here not redundant because if you ever get to
> > evaluating it, then irq->vcpu is null, and pending and enabled are set,
> > which means the oracle couldn't have returned null, could it?
> 
> In this case vcpu is always irq->target_vcpu, if I did the math
> correctly. So can this be NULL?
> Even if this is correct reasoning, I wonder if we optimize something
> prematurely here and rely on the current implementation of
> vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
> NULL pointer deference below (in the first spin_lock after the retry:
> label), so I'd rather keep this explicit check in here.

I'm really not a fan of building the correctness of one of the most
crucial parts of our code based on "let's add a few extra checks which
may not be necessary, just in case" kind of logic.

So let's be clear on why we have an if-statement here exactly:

As the comment says, if we can't move the IRQ, because it's already
assigned to somebody or if this IRQ is not pending or active, then it's
shouldn't be queued.

So the simple and all-encompassing check here is simply:

	if (irq->vcpu || !vcpu) {
		spin_unlock(&irq->irq_lock);
		return false;
	}

The only requirement for this to be correct is that the MMIO handler for
ISACTIVER to both set the active bit and the irq->vcpu pointer (and put
it on the AP list), without calling this function...).  That was my
quesiton below.

Because if that's not the case, you could end up here with irq->active
set, but irq->vcpu == NULL and !(pending && enabled) and you'd error
out, which means you would have to check explicitly for the active state
here as well, but I think that just becomes too messy.

So, just change this to what I propose and we can deal with the active
state MMIO handler separately.

> 
> > that would also explain why we don't have to re-check the same
> > conditions below...
> > 
> > or am I getting this wrong, because you could also have someone
> > explicitly setting the IRQ to active via trapped MMIO, in which case we
> > should be able to queue it without it being pending && enabled, which
> > would indicate that it's the other way around, you should only evaluate
> > !vcpu and kup the !(pending && enabled) part....?
> 
> You lost me here, which hints at the fragility of this optimization ;-)
> 
> >> +		spin_unlock(&irq->irq_lock);
> >> +		return false;
> >> +	}
> >> +
> >> +	/*
> >> +	 * We must unlock the irq lock to take the ap_list_lock where
> >> +	 * we are going to insert this new pending interrupt.
> >> +	 */
> >> +	spin_unlock(&irq->irq_lock);
> >> +
> >> +	/* someone can do stuff here, which we re-check below */
> >> +retry:
> >> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +	spin_lock(&irq->irq_lock);
> >> +
> >> +	/*
> >> +	 * Did something change behind our backs?
> >> +	 *
> >> +	 * There are two cases:
> >> +	 * 1) The irq became pending or active behind our backs and/or
> >> +	 *    the irq->vcpu field was set correspondingly when putting
> >> +	 *    the irq on an ap_list. Then drop the locks and return.
> >> +	 * 2) Someone changed the affinity on this irq behind our
> >> +	 *    backs and we are now holding the wrong ap_list_lock.
> >> +	 *    Then drop the locks and try the new VCPU.
> >> +	 */
> >> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
> > 
> > here I'm concerned about the active state again.
> 
> Mmmh, can you elaborate and sketch a case where the active state would
> cause trouble? This check is just here to avoid iterating on a no longer
> pending or enabled IRQ. I wonder if an active IRQ can really sneak into
> this function here in the first place?

After having gone through the series I think we should deal with
the active state queing directly in the vgic_mmio_write_sactive()
function.

But I still prefer to move the retry label to the very top of this
function, and simplify these two statemtns to the condition I suggested:

	if (unlinkely(irq->vcpu || vcpu != vgic_target_oracle(irq)))
		goto retry;

The cost is that we perform a few additional checks at runtime in the
case where the IRQ was migrated while we released a lock (rare), but I
think it simplifies the code.

> 
> > I feel like something more similar to my initial version of this patch
> > is what we really want:
> > 
> >        if (irq->vcpu || vcpu != vgic_target_oracle(irq))
> >            goto real_retry;
> > 
> > and read_retry is then a label at the very top of this function, before
> > the initial call to vgic_target_oracle()....
> > 
> >> +		spin_unlock(&irq->irq_lock);
> >> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +		return false;
> >> +	}
> >> +
> >> +	if (irq->target_vcpu != vcpu) {
> >> +		spin_unlock(&irq->irq_lock);
> >> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +
> >> +		vcpu = irq->target_vcpu;
> >> +		goto retry;
> >> +	}
> >> +
> >> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> >> +	irq->vcpu = vcpu;
> >> +
> >> +	spin_unlock(&irq->irq_lock);
> >> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +
> >> +	kvm_vcpu_kick(vcpu);
> >> +
> >> +	return true;
> >> +}
> >> +
> >> +static void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >> +				    u32 intid, bool level)
> >> +{
> >> +	struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
> >> +
> >> +	trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
> >> +
> >> +	BUG_ON(in_interrupt());
> > 
> > I don't remember why we thought it was a good idea to have this BUG_ON()
> > anymore.  Anyone?
> 
> Me neither. Is that because of the case where "kvm_notify_acked_irq
> calls kvm_set_irq" (which in turn may call this function)?
> I am happy to remove it, also as the old VGIC doesn't seem to have it.

ok, nuke it.

> 
> >> +
> >> +	spin_lock(&irq->irq_lock);
> >> +
> >> +	if (!vgic_validate_injection(irq, level)) {
> >> +		/* Nothing to see here, move along... */
> >> +		spin_unlock(&irq->irq_lock);
> >> +		return;
> >> +	}
> >> +
> >> +	if (irq->config == VGIC_CONFIG_LEVEL) {
> >> +		irq->line_level = level;
> >> +		irq->pending = level || irq->soft_pending;
> >> +	} else {
> >> +		irq->pending = true;
> >> +	}
> >> +
> >> +	vgic_queue_irq(kvm, irq);
> >> +}
> >> +
> >> +/**
> >> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
> >> + * @kvm:     The VM structure pointer
> >> + * @cpuid:   The CPU for PPIs
> >> + * @intid:   The INTID to inject a new state to.
> >> + *           must not be mapped to a HW interrupt.
> > 
> > stray line here?  I don't understand this bit about 'must not be mapped'
> > and I think that should be moved to the explanation below with some
> > rationale, and if important, perhaps guarded with a BUG_ON() ?
> 
> I think this is a copy&paste leftover from the old VGIC with the old way
> of handling mapped IRQs. Actually the implementations of
> kvm_vgic_inject_irq() and kvm_vgic_inject_mapped_irq() are now
> identical, so the former differentiation does not apply anymore. I will
> #define the latter to the former for the new VGIC and we should schedule
> the removal of the the "mapped" version when the old VGIC gets removed.

sounds good.

> 
> Btw: Are we OK with marking those cases which deserve some rework after
> the old VGIC is gone with some kind of TODO comments?
> 

I really think we should avoid merging TODOs as much as possible, but in
this case it's an exported interface function which could be hard to
work around with the current vgic, so it may be an exception to the
rule.

Thanks,
-Christoffer

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

* [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-04-06 14:23         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-06 14:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 05, 2016 at 06:28:55PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 29/03/16 22:16, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:29AM +0000, Andre Przywara wrote:
> >> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>
> >> Provide a vgic_queue_irq() function which decides whether a given
> >> IRQ needs to be queued to a VCPU's ap_list.
> >> This should be called whenever an IRQ became pending or got enabled,
> > 
> > becomes pending or enabled,
> > 
> >> either as a result of userspace injection, from in-kernel emulated
> >> devices like the architected timer or from MMIO accesses to the
> >> distributor emulation.
> >> Also provides the necessary functions to allow userland to inject an
> >> IRQ to a guest.
> > 
> > Since this is the first code that starts using our locking mechanism, we
> > add some (hopefully) clear documentation of our locking strategy and
> > requirements along with this patch.
> > 
> >> [Andre: refactor out vgic_queue_irq()]
> >>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  include/kvm/vgic/vgic.h  |   3 +
> >>  virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.h |   1 +
> >>  3 files changed, 185 insertions(+)
> >>
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> index 659f8b1..f32b284 100644
> >> --- a/include/kvm/vgic/vgic.h
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -178,6 +178,9 @@ struct vgic_cpu {
> >>  	struct list_head ap_list_head;
> >>  };
> >>  
> >> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> >> +			bool level);
> >> +
> >>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> >>  #define vgic_initialized(k)	(false)
> >>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> >> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> >> index 8e34916..a95aabc 100644
> >> --- a/virt/kvm/arm/vgic/vgic.c
> >> +++ b/virt/kvm/arm/vgic/vgic.c
> >> @@ -19,8 +19,25 @@
> >>  
> >>  #include "vgic.h"
> >>  
> >> +#define CREATE_TRACE_POINTS
> >> +#include "../trace.h"
> >> +
> >>  struct vgic_global kvm_vgic_global_state;
> >>  
> >> +/*
> >> + * Locking order is always:
> >> + *   vgic_cpu->ap_list_lock
> >> + *     vgic_irq->irq_lock
> >> + *
> >> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
> >> + *
> >> + * When taking more than one ap_list_lock at the same time, always take the
> >> + * lowest numbered VCPU's ap_list_lock first, so:
> >> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
> >> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
> >> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
> >> + */
> >> +
> >>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>  			      u32 intid)
> >>  {
> >> @@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
> >>  	return NULL;
> >>  }
> >> +
> >> +/**
> >> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
> >> + *
> >> + * @irq:	The irq to route. Must be already locked.
> 
>                                   ^^^^^^^^^^^^^^^^^^^^^^
> 
> >> + *
> >> + * Based on the current state of the interrupt (enabled, pending,
> >> + * active, vcpu and target_vcpu), compute the next vcpu this should be
> >> + * given to. Return NULL if this shouldn't be injected at all.
> >> + */
> >> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
> >> +{
> >> +	/* If the interrupt is active, it must stay on the current vcpu */
> >> +	if (irq->active)
> >> +		return irq->vcpu;
> > 
> > we are not taking a lock here.  What are the locking expectations?  If
> > the expectarions are that the IRQ is locked when calling this function,
> > can we have a BIG FAT COMMENT saying that then?
> 
> Do you mean really BIG FAT or is the above sufficient? (I guess not).
> I will make it more prominent.

well, maybe it doesn't have to be BIG FAT.  But I did miss the existing
comment.  I think it would be preferred to have a separate paragraph
explaining the locking expectaions, but perhaps I'm just
being stupid.

> 
> > It seems to me that we are somehow expecting irq->active and irq->vcpu
> > to be in sync, but that's not necessarily the case if the IRQ is not
> > locked.
> > 
> >> +
> >> +	/* If enabled and pending, it can migrate to a new one */
> > 
> > I think this comment should be rewritten to:
> > 
> > If the IRQ is not active but enabled and pending, we should direct it to
> > its configured target VCPU.
> > 
> >> +	if (irq->enabled && irq->pending)
> >> +		return irq->target_vcpu;
> >> +
> >> +	/* Otherwise, it is considered idle */
> > 
> > not sure what idle means here, I suggest something like:
> > 
> > If neither active nor pending and enabled, then this IRQ should not be
> > queued to any VCPU.
> > 
> >> +	return NULL;
> >> +}
> >> +
> >> +/*
> >> + * Only valid injection if changing level for level-triggered IRQs or for a
> >> + * rising edge.
> >> + */
> >> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
> >> +{
> >> +	switch (irq->config) {
> >> +	case VGIC_CONFIG_LEVEL:
> >> +		return irq->line_level != level;
> >> +	case VGIC_CONFIG_EDGE:
> >> +		return level;
> >> +	default:
> >> +		BUG();
> > 
> > is the default case there for making the compiler happy or can we just
> > get rid of it?
> 
> Just removing it was fine (for GCC 5.3.0, at least).
> 
> >> +	}
> >> +}
> >> +
> >> +/*
> >> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
> >> + * Do the queuing if necessary, taking the right locks in the right order.
> >> + * Returns true when the IRQ was queued, false otherwise.
> >> + *
> >> + * Needs to be entered with the IRQ lock already held, but will return
> >> + * with all locks dropped.
> >> + */
> >> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)
> > 
> > should we name this vgic_try_queue_irq_locked ?
> 
> Mmh, since it (re-)tries quite hard I am not sure _try_ would be
> misleading. Basically it queues the IRQ whenever possible and/or
> sensible. Having _unlock in it like you suggested in another reply makes
> more sense, I think.

agreed

> 
> >> +{
> >> +	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);
> > 
> > should we have something like BUG_ON(!spin_is_locked(irq->irq_lock));
> > here?
> > 
> > Not sure if there's some bug checking here which is only emitted if a
> > user select CONFIG_CHECK_SOME_LOCKING_THINGS that we could use...?
> 
> There is CONFIG_DEBUG_SPINLOCK, but I couldn't find some conditional
> debug macro suitable for the purpose. I defined one now for the file
> only (since we have quite some users here).
> 
> >> +
> >> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
> >> +		/*
> >> +		 * If this IRQ is already on a VCPU's ap_list, then it
> >> +		 * cannot be moved or modified and there is no more work for
> >> +		 * us to do.
> >> +		 *
> >> +		 * Otherwise, if the irq is not pending and enabled, it does
> >> +		 * not need to be inserted into an ap_list and there is also
> >> +		 * no more work for us to do.
> >> +		 */
> > 
> > is the !vcpu check here not redundant because if you ever get to
> > evaluating it, then irq->vcpu is null, and pending and enabled are set,
> > which means the oracle couldn't have returned null, could it?
> 
> In this case vcpu is always irq->target_vcpu, if I did the math
> correctly. So can this be NULL?
> Even if this is correct reasoning, I wonder if we optimize something
> prematurely here and rely on the current implementation of
> vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
> NULL pointer deference below (in the first spin_lock after the retry:
> label), so I'd rather keep this explicit check in here.

I'm really not a fan of building the correctness of one of the most
crucial parts of our code based on "let's add a few extra checks which
may not be necessary, just in case" kind of logic.

So let's be clear on why we have an if-statement here exactly:

As the comment says, if we can't move the IRQ, because it's already
assigned to somebody or if this IRQ is not pending or active, then it's
shouldn't be queued.

So the simple and all-encompassing check here is simply:

	if (irq->vcpu || !vcpu) {
		spin_unlock(&irq->irq_lock);
		return false;
	}

The only requirement for this to be correct is that the MMIO handler for
ISACTIVER to both set the active bit and the irq->vcpu pointer (and put
it on the AP list), without calling this function...).  That was my
quesiton below.

Because if that's not the case, you could end up here with irq->active
set, but irq->vcpu == NULL and !(pending && enabled) and you'd error
out, which means you would have to check explicitly for the active state
here as well, but I think that just becomes too messy.

So, just change this to what I propose and we can deal with the active
state MMIO handler separately.

> 
> > that would also explain why we don't have to re-check the same
> > conditions below...
> > 
> > or am I getting this wrong, because you could also have someone
> > explicitly setting the IRQ to active via trapped MMIO, in which case we
> > should be able to queue it without it being pending && enabled, which
> > would indicate that it's the other way around, you should only evaluate
> > !vcpu and kup the !(pending && enabled) part....?
> 
> You lost me here, which hints at the fragility of this optimization ;-)
> 
> >> +		spin_unlock(&irq->irq_lock);
> >> +		return false;
> >> +	}
> >> +
> >> +	/*
> >> +	 * We must unlock the irq lock to take the ap_list_lock where
> >> +	 * we are going to insert this new pending interrupt.
> >> +	 */
> >> +	spin_unlock(&irq->irq_lock);
> >> +
> >> +	/* someone can do stuff here, which we re-check below */
> >> +retry:
> >> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +	spin_lock(&irq->irq_lock);
> >> +
> >> +	/*
> >> +	 * Did something change behind our backs?
> >> +	 *
> >> +	 * There are two cases:
> >> +	 * 1) The irq became pending or active behind our backs and/or
> >> +	 *    the irq->vcpu field was set correspondingly when putting
> >> +	 *    the irq on an ap_list. Then drop the locks and return.
> >> +	 * 2) Someone changed the affinity on this irq behind our
> >> +	 *    backs and we are now holding the wrong ap_list_lock.
> >> +	 *    Then drop the locks and try the new VCPU.
> >> +	 */
> >> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
> > 
> > here I'm concerned about the active state again.
> 
> Mmmh, can you elaborate and sketch a case where the active state would
> cause trouble? This check is just here to avoid iterating on a no longer
> pending or enabled IRQ. I wonder if an active IRQ can really sneak into
> this function here in the first place?

After having gone through the series I think we should deal with
the active state queing directly in the vgic_mmio_write_sactive()
function.

But I still prefer to move the retry label to the very top of this
function, and simplify these two statemtns to the condition I suggested:

	if (unlinkely(irq->vcpu || vcpu != vgic_target_oracle(irq)))
		goto retry;

The cost is that we perform a few additional checks at runtime in the
case where the IRQ was migrated while we released a lock (rare), but I
think it simplifies the code.

> 
> > I feel like something more similar to my initial version of this patch
> > is what we really want:
> > 
> >        if (irq->vcpu || vcpu != vgic_target_oracle(irq))
> >            goto real_retry;
> > 
> > and read_retry is then a label at the very top of this function, before
> > the initial call to vgic_target_oracle()....
> > 
> >> +		spin_unlock(&irq->irq_lock);
> >> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +		return false;
> >> +	}
> >> +
> >> +	if (irq->target_vcpu != vcpu) {
> >> +		spin_unlock(&irq->irq_lock);
> >> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +
> >> +		vcpu = irq->target_vcpu;
> >> +		goto retry;
> >> +	}
> >> +
> >> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> >> +	irq->vcpu = vcpu;
> >> +
> >> +	spin_unlock(&irq->irq_lock);
> >> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +
> >> +	kvm_vcpu_kick(vcpu);
> >> +
> >> +	return true;
> >> +}
> >> +
> >> +static void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >> +				    u32 intid, bool level)
> >> +{
> >> +	struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
> >> +
> >> +	trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
> >> +
> >> +	BUG_ON(in_interrupt());
> > 
> > I don't remember why we thought it was a good idea to have this BUG_ON()
> > anymore.  Anyone?
> 
> Me neither. Is that because of the case where "kvm_notify_acked_irq
> calls kvm_set_irq" (which in turn may call this function)?
> I am happy to remove it, also as the old VGIC doesn't seem to have it.

ok, nuke it.

> 
> >> +
> >> +	spin_lock(&irq->irq_lock);
> >> +
> >> +	if (!vgic_validate_injection(irq, level)) {
> >> +		/* Nothing to see here, move along... */
> >> +		spin_unlock(&irq->irq_lock);
> >> +		return;
> >> +	}
> >> +
> >> +	if (irq->config == VGIC_CONFIG_LEVEL) {
> >> +		irq->line_level = level;
> >> +		irq->pending = level || irq->soft_pending;
> >> +	} else {
> >> +		irq->pending = true;
> >> +	}
> >> +
> >> +	vgic_queue_irq(kvm, irq);
> >> +}
> >> +
> >> +/**
> >> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
> >> + * @kvm:     The VM structure pointer
> >> + * @cpuid:   The CPU for PPIs
> >> + * @intid:   The INTID to inject a new state to.
> >> + *           must not be mapped to a HW interrupt.
> > 
> > stray line here?  I don't understand this bit about 'must not be mapped'
> > and I think that should be moved to the explanation below with some
> > rationale, and if important, perhaps guarded with a BUG_ON() ?
> 
> I think this is a copy&paste leftover from the old VGIC with the old way
> of handling mapped IRQs. Actually the implementations of
> kvm_vgic_inject_irq() and kvm_vgic_inject_mapped_irq() are now
> identical, so the former differentiation does not apply anymore. I will
> #define the latter to the former for the new VGIC and we should schedule
> the removal of the the "mapped" version when the old VGIC gets removed.

sounds good.

> 
> Btw: Are we OK with marking those cases which deserve some rework after
> the old VGIC is gone with some kind of TODO comments?
> 

I really think we should avoid merging TODOs as much as possible, but in
this case it's an exported interface function which could be hard to
work around with the current vgic, so it may be an exception to the
rule.

Thanks,
-Christoffer

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

* Re: [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
  2016-04-05 17:57       ` Andre Przywara
@ 2016-04-06 14:34         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-06 14:34 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Tue, Apr 05, 2016 at 06:57:57PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 30/03/16 14:53, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> Implement the functionality for syncing IRQs between our emulation
> >> and the list registers, which represent the guest's view of IRQs.
> >> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> >> which gets called on guest entry and exit.
> > 
> > I thought we agreed to split this up in a generic part and then GICv2
> > and GICv3 parts following, but ok, I'll look through this code, but I
> > strongly suggest splitting it up for the next posting.
> 
> Right, I guess I missed this one. I abandoned the idea of splitting the
> patch _series_ between a v2 and a v3 series (to avoid agreeing on the v2
> implementation too early without taking the v3 requirements into
> account), so I guess I skipped the comment about this patch split.
> I will try to split off the generic part of the code.
> 

It still just feels a bit messy and random at places when you go trough
the initial part of the patch series (once we get to the MMIO stuff,
it's all well-structured) so that's the background for my comment.  Oh
well.

> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  include/kvm/vgic/vgic.h     |   4 +
> >>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.h    |   4 +
> >>  4 files changed, 373 insertions(+)
> >>
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> index f32b284..986f23f 100644
> >> --- a/include/kvm/vgic/vgic.h
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> >>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> >>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> >>  
> >> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> >> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> >> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> >> +
> >>  /**
> >>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
> >>   *
> >> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >> index 0bf6f27..1cec423 100644
> >> --- a/virt/kvm/arm/vgic/vgic-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >> @@ -14,11 +14,172 @@
> >>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >>   */
> >>  
> >> +#include <linux/irqchip/arm-gic.h>
> >>  #include <linux/kvm.h>
> >>  #include <linux/kvm_host.h>
> >>  
> >>  #include "vgic.h"
> >>  
> >> +/*
> >> + * Call this function to convert a u64 value to an unsigned long * bitmask
> >> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> >> + *
> >> + * Warning: Calling this function may modify *val.
> >> + */
> >> +static unsigned long *u64_to_bitmask(u64 *val)
> >> +{
> >> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> >> +	*val = (*val >> 32) | (*val << 32);
> >> +#endif
> >> +	return (unsigned long *)val;
> >> +}
> >> +
> >> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> >> +		u64 eisr = cpuif->vgic_eisr;
> >> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> >> +		int lr;
> >> +
> >> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> >> +			struct vgic_irq *irq;
> >> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >> +
> >> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >> +
> >> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
> >> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> >> +
> >> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >> +
> >> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
> > 
> > we just had a warning above if the LR state was set, so how do we
> > expect this to be modified in the mean time?
> 
> I guess the warning is just a warning, so code execution continues in
> this case, right?
> 

yeah, but it's a warning saying "you're VM is messed up, you're probably
in lala land now", so I think you can just get rid of this.

The WARN_ON really means that (a) we have a software BUG, (b) hardware
is broken, or (c) we misread the architecture.  In either case, it's not
about trying to recover gracefully, our job is just to tell the user
that your VM is busted without bringing the whole system down with a
BUG_ON.

> > The following line caters for the famous hardware race, right?  If so, I think it deserved a comment:
> > 
> > /*
> >  * The hardware doesn't guarantee that the LR's bit is set in the ELRSR
> >  * despite the virtual interrupt being EOIed and generating a
> >  * maintenance interrupt.  Force the bit to be set.
> >  */
> > 
> >> +			cpuif->vgic_elrsr |= 1ULL << lr;
> >> +		}
> >> +	}
> >> +
> >> +	/* check and disable underflow maintenance IRQ */
> > 
> > s/check and d/D/
> > 
> >> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> > 
> > I think the above should be moved to fold_lr_state
> > 
> >> +
> >> +	/*
> >> +	 * In the next iterations of the vcpu loop, if we sync the
> >> +	 * vgic state after flushing it, but before entering the guest
> >> +	 * (this happens for pending signals and vmid rollovers), then
> >> +	 * make sure we don't pick up any old maintenance interrupts
> >> +	 * here.
> >> +	 */
> >> +	cpuif->vgic_eisr = 0;
> >> +}
> >> +
> >> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> >> +}
> >> +
> >> +/*
> >> + * transfer the content of the LRs back into the corresponding ap_list:
> >> + * - active bit is transferred as is
> >> + * - pending bit is
> >> + *   - transferred as is in case of edge sensitive IRQs
> >> + *   - set to the line-level (resample time) for level sensitive IRQs
> >> + */
> >> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +	int lr;
> >> +
> >> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> >> +		u32 val = cpuif->vgic_lr[lr];
> >> +		u32 intid = val & GICH_LR_VIRTUALID;
> >> +		struct vgic_irq *irq;
> >> +
> >> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/* Always preserve the active bit */
> >> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> >> +
> >> +		/* Edge is the only case where we preserve the pending bit */
> >> +		if (irq->config == VGIC_CONFIG_EDGE &&
> >> +		    (val & GICH_LR_PENDING_BIT)) {
> >> +			irq->pending = true;
> >> +
> >> +			if (intid < VGIC_NR_SGIS) {
> >> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> >> +
> >> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> > 
> > Are we happy with relying on all the remaining bits being 0 here or
> > should we define a proper CPUID mask?
> 
> Not sure which remaining bits you mean? GICH_LR_PHYSID_CPUID is a mask
> (admittedly a bit misnamed).
> Or what do I miss here?

The mask covers more bits than the CPUID field, but I think they're RES0
in the spec, and I guess we rely on that here?

> 
> >> +				irq->source |= (1 << cpuid);
> >> +			}
> >> +		}
> >> +
> >> +		/* Clear soft pending state when level IRQs have been acked */
> >> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> >> +		    !(val & GICH_LR_PENDING_BIT)) {
> >> +			irq->soft_pending = false;
> >> +			irq->pending = irq->line_level;
> >> +		}
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +	}
> >> +}
> >> +
> >> +/*
> >> + * Populates the particular LR with the state of a given IRQ:
> >> + * - for an edge sensitive IRQ the pending state is reset in the struct
> > 
> > s/reset/cleared/
> > s/the struct/the vgic_irq struct/
> > 
> >> + * - for a level sensitive IRQ the pending state value is unchanged;
> >> + *   it will be resampled on deactivation
> > 
> > s/
> > it will be resampled on deactivation/
> > it is dictated directly by the input level/
> > 
> >> + *
> >> + * If irq is not NULL, the irq_lock must be hold already by the caller.
> > 
> > s/hold/held/
> > 
> >> + * If irq is NULL, the respective LR gets cleared.
> > 
> > If @irq describes an SGI with multiple sources, we choose the
> > lowest-numbered source VCPU and clear that bit in the source bitmap.
> > 
> >> + */
> >> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> >> +{
> >> +	u32 val;
> >> +
> >> +	if (!irq) {
> >> +		val = 0;
> >> +		goto out;
> >> +	}
> > 
> > I'm not convinced about keeping this functionality in this function.
> > 
> > Wouldn't it be much more clear to have vgic_clear_lr() as a separate
> > function?
> 
> Yeah, I agree. Also found it cumbersome to explicitly call this function
> with a NULL argument to clear it.
> 
> >> +
> >> +	val = irq->intid;
> >> +
> >> +	if (irq->pending) {
> >> +		val |= GICH_LR_PENDING_BIT;
> >> +
> >> +		if (irq->config == VGIC_CONFIG_EDGE)
> >> +			irq->pending = false;
> >> +
> >> +		if (irq->intid < VGIC_NR_SGIS) {
> >> +			u32 src = ffs(irq->source);
> > 
> > can't you do src = __ffs(irq->source) here to avoid the (src - 1) below?
> > 
> >> +
> >> +			BUG_ON(!src);
> >> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> >> +			irq->source &= ~(1 << (src - 1));
> >> +			if (irq->source)
> >> +				irq->pending = true;
> >> +		}
> >> +	}
> >> +
> >> +	if (irq->active)
> >> +		val |= GICH_LR_ACTIVE_BIT;
> >> +
> >> +	if (irq->hw) {
> >> +		val |= GICH_LR_HW;
> >> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> >> +	} else {
> >> +		if (irq->config == VGIC_CONFIG_LEVEL)
> >> +			val |= GICH_LR_EOI;
> >> +	}
> >> +
> >> +out:
> >> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
> >> +}
> >> +
> >>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
> >>  {
> >>  	struct vgic_dist *dist = &kvm->arch.vgic;
> >> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> >> index 29c753e..90a85bf 100644
> >> --- a/virt/kvm/arm/vgic/vgic.c
> >> +++ b/virt/kvm/arm/vgic/vgic.c
> >> @@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> >>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
> >>  	return 0;
> >>  }
> >> +
> >> +/**
> >> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> >> + *
> >> + * @vcpu: The VCPU pointer
> >> + *
> >> + * Go over the list of "interesting" interrupts, and prune those that we
> >> + * won't have to consider in the near future.
> >> + */
> >> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> >> +	struct vgic_irq *irq, *tmp;
> >> +
> >> +retry:
> >> +	spin_lock(&vgic_cpu->ap_list_lock);
> >> +
> >> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> >> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		BUG_ON(vcpu != irq->vcpu);
> >> +
> >> +		target_vcpu = vgic_target_oracle(irq);
> >> +
> >> +		if (!target_vcpu) {
> >> +			/*
> >> +			 * We don't need to process this interrupt any
> >> +			 * further, move it off the list.
> >> +			 */
> >> +			list_del_init(&irq->ap_list);
> > 
> > why list_del_init and not list_del here?  do we ever do list_empty() on
> > the &irq->ap_list ?
> 
> Why not? I think we discussed the usage of list_empty() for determining
> if the VCPU is ready to run.

yeah, on the head of the list in the vcpu structure, not on the
individual IRQ structs.

> What is your concern about list_del_init? Is that too costly?
> 

I'm not sure if it's measurable, but I generally don't have a feeling
that we have CPU cycles to spare that we need to get rid of:)


> >> +			irq->vcpu = NULL;
> >> +			spin_unlock(&irq->irq_lock);
> >> +			continue;
> >> +		}
> >> +
> >> +		if (target_vcpu == vcpu) {
> >> +			/* We're on the right CPU */
> >> +			spin_unlock(&irq->irq_lock);
> >> +			continue;
> >> +		}
> >> +
> >> +		/* This interrupt looks like it has to be migrated. */
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +		spin_unlock(&vgic_cpu->ap_list_lock);
> >> +
> >> +		/*
> >> +		 * Ensure locking order by always locking the smallest
> >> +		 * ID first.
> >> +		 */
> >> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> >> +			vcpuA = vcpu;
> >> +			vcpuB = target_vcpu;
> >> +		} else {
> >> +			vcpuA = target_vcpu;
> >> +			vcpuB = vcpu;
> >> +		}
> >> +
> >> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> >> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/*
> >> +		 * If the affinity has been preserved, move the
> >> +		 * interrupt around. Otherwise, it means things have
> >> +		 * changed while the interrupt was unlocked, and we
> >> +		 * need to replay this.
> >> +		 *
> >> +		 * In all cases, we cannot trust the list not to have
> >> +		 * changed, so we restart from the beginning.
> >> +		 */
> >> +		if (target_vcpu == vgic_target_oracle(irq)) {
> >> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> >> +
> >> +			list_del_init(&irq->ap_list);
> > 
> > again, why list_del_init and not just list_del ?
> > 
> >> +			irq->vcpu = target_vcpu;
> >> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> >> +		}
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> >> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> >> +		goto retry;
> >> +	}
> >> +
> >> +	spin_unlock(&vgic_cpu->ap_list_lock);
> >> +}
> >> +
> >> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_process_maintenance(vcpu);
> >> +	else
> >> +		WARN(1, "GICv3 Not Implemented\n");
> >> +}
> >> +
> >> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_fold_lr_state(vcpu);
> >> +	else
> >> +		WARN(1, "GICv3 Not Implemented\n");
> >> +}
> >> +
> >> +/*
> >> + * Requires the ap_lock to be held.
> >> + * If irq is not NULL, requires the IRQ lock to be held as well.
> >> + * If irq is NULL, the list register gets cleared.
> >> + */
> >> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> >> +				    struct vgic_irq *irq, int lr)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_populate_lr(vcpu, irq, lr);
> >> +	else
> >> +		WARN(1, "GICv3 Not Implemented\n");
> >> +}
> >> +
> >> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_set_underflow(vcpu);
> >> +	else
> >> +		WARN(1, "GICv3 Not Implemented\n");
> >> +}
> >> +
> >> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> >> +	struct vgic_irq *irq;
> >> +	int count = 0;
> >> +
> >> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> >> +		spin_lock(&irq->irq_lock);
> >> +		/* GICv2 SGIs can count for more than one... */
> >> +		if (irq->intid < VGIC_NR_SGIS && irq->source)
> > 
> > how can we have an SGI on an AP list without the irq->source field set?
> > 
> > Is the irq->source check to cater for GICv3?
> 
> Yes, in the v3 case irq->source is 0, so the hweight is zero as well.
> 

ah right, missed that.

> >> +			count += hweight8(irq->source);
> >> +		else
> >> +			count++;
> >> +		spin_unlock(&irq->irq_lock);
> >> +	}
> >> +	return count;
> > 
> > this does feel like an awful lot of code on each entry.
> 
> Is this really a lot of code? I count two comparisons and an inc, or the
> hweight8 in case of SGIs. The latter implementation doesn't look to bad
> either (given that it all happens in a register).
> Or is there some code I missed?

The spin_lock inside the loop is what scared me, but you're right that
by far the common case is that the list is empty, so this is most likely
premature.

> 
> > I'm wondering
> > if we should have a count on each vgic_cpu containing the length of the
> > AP list which is then adjusted via the queue and removal functions?
> 
> That sounds like some work to make sure we cover all the cases. Also we
> would need to care about the consistency of this.

Not too scared of that, using an atomic counter and given that we have
the queue function, it's one place plus some MMIO handlers that need the
attention.  But yes, we can just fix that later if it makes a
difference, you can leave it for now.

> 
> >> +}
> >> +
> >> +/* requires the vcpu ap_lock to be held */
> > 
> > s/ap_lock/ap_list_lock/
> > 
> >> +static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
> > 
> > I'm not in love with the fact that we have two separate functions named:
> > 
> >   vgic_populate_lrs  and
> >   vgic_populate_lr
> > 
> > perhaps this could be changed to 'vgic_flush_ap_list' ?
> 
> Agreed.
> 
> > 
> >> +{
> >> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> >> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> >> +	struct vgic_irq *irq;
> >> +	int count = 0;
> >> +
> >> +	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
> >> +		vgic_set_underflow(vcpu);
> >> +		vgic_sort_ap_list(vcpu);
> >> +	}
> >> +
> >> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> >> +			goto next;
> >> +
> >> +		/*
> >> +		 * If we get an SGI with multiple sources, try to get
> >> +		 * them in all at once.
> >> +		 */
> >> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
> >> +		    irq->intid < VGIC_NR_SGIS) {
> > 
> > I wonder if a lot of this code would be more readable if we added and
> > used the following primitives:
> > vgic_irq_is_sgi()
> > vgic_irq_is_ppi()
> > vgic_irq_is_spi()
> 
> If that doesn't break 80 characters ... ;-)
> 

eh, it's already on its own line...

> >> +			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
> >> +				vgic_populate_lr(vcpu, irq, count++);
> >> +		} else {
> >> +			vgic_populate_lr(vcpu, irq, count++);
> >> +		}
> > 
> > this stuff about the SGIs is really dense, so I'm wondering if it's more
> > clean to make it even more dense and rewrite the whole if-statement to:
> > 
> > 	do {
> > 		vgic_populate(vcpu, irq, count++);
> > 	} while (irq->source && count < vgic.nr_lr);
> > 
> > (btw. I believe all these places referencing the nr_lr in the vgic_cpu
> > struct could use the global state structure instead).
> 
> Good point. We should convert all the places where this is easily doable
> already.
> 
> > 
> >> +
> >> +next:
> >> +		spin_unlock(&irq->irq_lock);
> >> +
> >> +		if (count == vcpu->arch.vgic_cpu.nr_lr)
> >> +			break;
> >> +	}
> >> +
> >> +	vcpu->arch.vgic_cpu.used_lrs = count;
> >> +
> >> +	/* Nuke remaining LRs */
> >> +	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
> >> +		vgic_populate_lr(vcpu, NULL, count);
> > 
> > should we not change this to adhere to the optimizations Marc
> > implemented for the current VGIC (i.e. clear the LRs on sync+init, and
> > only write what you need here)?
> 
> Those optimizations were not in the branch I based this series on.
> I will take a look with the new series being based on 4.6-rc (added
> live_lrs already).
> 

Thinking about this some more, probably we just want to respin the
series as it is currently, and then apply optimizations similar to what
we have for the legacy code on top of it.

Someone else than you could do that as well.

> 
> BTW: Thanks for the thorough review. I agree and will change all your
> comments I didn't explicitly replied on.
> 

Thanks for doing all the heavy lifting on this one!

-Christoffer

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

* [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
@ 2016-04-06 14:34         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-06 14:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 05, 2016 at 06:57:57PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 30/03/16 14:53, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> Implement the functionality for syncing IRQs between our emulation
> >> and the list registers, which represent the guest's view of IRQs.
> >> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> >> which gets called on guest entry and exit.
> > 
> > I thought we agreed to split this up in a generic part and then GICv2
> > and GICv3 parts following, but ok, I'll look through this code, but I
> > strongly suggest splitting it up for the next posting.
> 
> Right, I guess I missed this one. I abandoned the idea of splitting the
> patch _series_ between a v2 and a v3 series (to avoid agreeing on the v2
> implementation too early without taking the v3 requirements into
> account), so I guess I skipped the comment about this patch split.
> I will try to split off the generic part of the code.
> 

It still just feels a bit messy and random at places when you go trough
the initial part of the patch series (once we get to the MMIO stuff,
it's all well-structured) so that's the background for my comment.  Oh
well.

> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  include/kvm/vgic/vgic.h     |   4 +
> >>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.h    |   4 +
> >>  4 files changed, 373 insertions(+)
> >>
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> index f32b284..986f23f 100644
> >> --- a/include/kvm/vgic/vgic.h
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> >>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> >>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> >>  
> >> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> >> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> >> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> >> +
> >>  /**
> >>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
> >>   *
> >> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >> index 0bf6f27..1cec423 100644
> >> --- a/virt/kvm/arm/vgic/vgic-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >> @@ -14,11 +14,172 @@
> >>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >>   */
> >>  
> >> +#include <linux/irqchip/arm-gic.h>
> >>  #include <linux/kvm.h>
> >>  #include <linux/kvm_host.h>
> >>  
> >>  #include "vgic.h"
> >>  
> >> +/*
> >> + * Call this function to convert a u64 value to an unsigned long * bitmask
> >> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> >> + *
> >> + * Warning: Calling this function may modify *val.
> >> + */
> >> +static unsigned long *u64_to_bitmask(u64 *val)
> >> +{
> >> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> >> +	*val = (*val >> 32) | (*val << 32);
> >> +#endif
> >> +	return (unsigned long *)val;
> >> +}
> >> +
> >> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> >> +		u64 eisr = cpuif->vgic_eisr;
> >> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> >> +		int lr;
> >> +
> >> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> >> +			struct vgic_irq *irq;
> >> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >> +
> >> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >> +
> >> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
> >> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> >> +
> >> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >> +
> >> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
> > 
> > we just had a warning above if the LR state was set, so how do we
> > expect this to be modified in the mean time?
> 
> I guess the warning is just a warning, so code execution continues in
> this case, right?
> 

yeah, but it's a warning saying "you're VM is messed up, you're probably
in lala land now", so I think you can just get rid of this.

The WARN_ON really means that (a) we have a software BUG, (b) hardware
is broken, or (c) we misread the architecture.  In either case, it's not
about trying to recover gracefully, our job is just to tell the user
that your VM is busted without bringing the whole system down with a
BUG_ON.

> > The following line caters for the famous hardware race, right?  If so, I think it deserved a comment:
> > 
> > /*
> >  * The hardware doesn't guarantee that the LR's bit is set in the ELRSR
> >  * despite the virtual interrupt being EOIed and generating a
> >  * maintenance interrupt.  Force the bit to be set.
> >  */
> > 
> >> +			cpuif->vgic_elrsr |= 1ULL << lr;
> >> +		}
> >> +	}
> >> +
> >> +	/* check and disable underflow maintenance IRQ */
> > 
> > s/check and d/D/
> > 
> >> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> > 
> > I think the above should be moved to fold_lr_state
> > 
> >> +
> >> +	/*
> >> +	 * In the next iterations of the vcpu loop, if we sync the
> >> +	 * vgic state after flushing it, but before entering the guest
> >> +	 * (this happens for pending signals and vmid rollovers), then
> >> +	 * make sure we don't pick up any old maintenance interrupts
> >> +	 * here.
> >> +	 */
> >> +	cpuif->vgic_eisr = 0;
> >> +}
> >> +
> >> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> >> +}
> >> +
> >> +/*
> >> + * transfer the content of the LRs back into the corresponding ap_list:
> >> + * - active bit is transferred as is
> >> + * - pending bit is
> >> + *   - transferred as is in case of edge sensitive IRQs
> >> + *   - set to the line-level (resample time) for level sensitive IRQs
> >> + */
> >> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +	int lr;
> >> +
> >> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> >> +		u32 val = cpuif->vgic_lr[lr];
> >> +		u32 intid = val & GICH_LR_VIRTUALID;
> >> +		struct vgic_irq *irq;
> >> +
> >> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/* Always preserve the active bit */
> >> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> >> +
> >> +		/* Edge is the only case where we preserve the pending bit */
> >> +		if (irq->config == VGIC_CONFIG_EDGE &&
> >> +		    (val & GICH_LR_PENDING_BIT)) {
> >> +			irq->pending = true;
> >> +
> >> +			if (intid < VGIC_NR_SGIS) {
> >> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> >> +
> >> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> > 
> > Are we happy with relying on all the remaining bits being 0 here or
> > should we define a proper CPUID mask?
> 
> Not sure which remaining bits you mean? GICH_LR_PHYSID_CPUID is a mask
> (admittedly a bit misnamed).
> Or what do I miss here?

The mask covers more bits than the CPUID field, but I think they're RES0
in the spec, and I guess we rely on that here?

> 
> >> +				irq->source |= (1 << cpuid);
> >> +			}
> >> +		}
> >> +
> >> +		/* Clear soft pending state when level IRQs have been acked */
> >> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> >> +		    !(val & GICH_LR_PENDING_BIT)) {
> >> +			irq->soft_pending = false;
> >> +			irq->pending = irq->line_level;
> >> +		}
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +	}
> >> +}
> >> +
> >> +/*
> >> + * Populates the particular LR with the state of a given IRQ:
> >> + * - for an edge sensitive IRQ the pending state is reset in the struct
> > 
> > s/reset/cleared/
> > s/the struct/the vgic_irq struct/
> > 
> >> + * - for a level sensitive IRQ the pending state value is unchanged;
> >> + *   it will be resampled on deactivation
> > 
> > s/
> > it will be resampled on deactivation/
> > it is dictated directly by the input level/
> > 
> >> + *
> >> + * If irq is not NULL, the irq_lock must be hold already by the caller.
> > 
> > s/hold/held/
> > 
> >> + * If irq is NULL, the respective LR gets cleared.
> > 
> > If @irq describes an SGI with multiple sources, we choose the
> > lowest-numbered source VCPU and clear that bit in the source bitmap.
> > 
> >> + */
> >> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> >> +{
> >> +	u32 val;
> >> +
> >> +	if (!irq) {
> >> +		val = 0;
> >> +		goto out;
> >> +	}
> > 
> > I'm not convinced about keeping this functionality in this function.
> > 
> > Wouldn't it be much more clear to have vgic_clear_lr() as a separate
> > function?
> 
> Yeah, I agree. Also found it cumbersome to explicitly call this function
> with a NULL argument to clear it.
> 
> >> +
> >> +	val = irq->intid;
> >> +
> >> +	if (irq->pending) {
> >> +		val |= GICH_LR_PENDING_BIT;
> >> +
> >> +		if (irq->config == VGIC_CONFIG_EDGE)
> >> +			irq->pending = false;
> >> +
> >> +		if (irq->intid < VGIC_NR_SGIS) {
> >> +			u32 src = ffs(irq->source);
> > 
> > can't you do src = __ffs(irq->source) here to avoid the (src - 1) below?
> > 
> >> +
> >> +			BUG_ON(!src);
> >> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> >> +			irq->source &= ~(1 << (src - 1));
> >> +			if (irq->source)
> >> +				irq->pending = true;
> >> +		}
> >> +	}
> >> +
> >> +	if (irq->active)
> >> +		val |= GICH_LR_ACTIVE_BIT;
> >> +
> >> +	if (irq->hw) {
> >> +		val |= GICH_LR_HW;
> >> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> >> +	} else {
> >> +		if (irq->config == VGIC_CONFIG_LEVEL)
> >> +			val |= GICH_LR_EOI;
> >> +	}
> >> +
> >> +out:
> >> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
> >> +}
> >> +
> >>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
> >>  {
> >>  	struct vgic_dist *dist = &kvm->arch.vgic;
> >> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> >> index 29c753e..90a85bf 100644
> >> --- a/virt/kvm/arm/vgic/vgic.c
> >> +++ b/virt/kvm/arm/vgic/vgic.c
> >> @@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> >>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
> >>  	return 0;
> >>  }
> >> +
> >> +/**
> >> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> >> + *
> >> + * @vcpu: The VCPU pointer
> >> + *
> >> + * Go over the list of "interesting" interrupts, and prune those that we
> >> + * won't have to consider in the near future.
> >> + */
> >> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> >> +	struct vgic_irq *irq, *tmp;
> >> +
> >> +retry:
> >> +	spin_lock(&vgic_cpu->ap_list_lock);
> >> +
> >> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> >> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		BUG_ON(vcpu != irq->vcpu);
> >> +
> >> +		target_vcpu = vgic_target_oracle(irq);
> >> +
> >> +		if (!target_vcpu) {
> >> +			/*
> >> +			 * We don't need to process this interrupt any
> >> +			 * further, move it off the list.
> >> +			 */
> >> +			list_del_init(&irq->ap_list);
> > 
> > why list_del_init and not list_del here?  do we ever do list_empty() on
> > the &irq->ap_list ?
> 
> Why not? I think we discussed the usage of list_empty() for determining
> if the VCPU is ready to run.

yeah, on the head of the list in the vcpu structure, not on the
individual IRQ structs.

> What is your concern about list_del_init? Is that too costly?
> 

I'm not sure if it's measurable, but I generally don't have a feeling
that we have CPU cycles to spare that we need to get rid of:)


> >> +			irq->vcpu = NULL;
> >> +			spin_unlock(&irq->irq_lock);
> >> +			continue;
> >> +		}
> >> +
> >> +		if (target_vcpu == vcpu) {
> >> +			/* We're on the right CPU */
> >> +			spin_unlock(&irq->irq_lock);
> >> +			continue;
> >> +		}
> >> +
> >> +		/* This interrupt looks like it has to be migrated. */
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +		spin_unlock(&vgic_cpu->ap_list_lock);
> >> +
> >> +		/*
> >> +		 * Ensure locking order by always locking the smallest
> >> +		 * ID first.
> >> +		 */
> >> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> >> +			vcpuA = vcpu;
> >> +			vcpuB = target_vcpu;
> >> +		} else {
> >> +			vcpuA = target_vcpu;
> >> +			vcpuB = vcpu;
> >> +		}
> >> +
> >> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> >> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/*
> >> +		 * If the affinity has been preserved, move the
> >> +		 * interrupt around. Otherwise, it means things have
> >> +		 * changed while the interrupt was unlocked, and we
> >> +		 * need to replay this.
> >> +		 *
> >> +		 * In all cases, we cannot trust the list not to have
> >> +		 * changed, so we restart from the beginning.
> >> +		 */
> >> +		if (target_vcpu == vgic_target_oracle(irq)) {
> >> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> >> +
> >> +			list_del_init(&irq->ap_list);
> > 
> > again, why list_del_init and not just list_del ?
> > 
> >> +			irq->vcpu = target_vcpu;
> >> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> >> +		}
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> >> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> >> +		goto retry;
> >> +	}
> >> +
> >> +	spin_unlock(&vgic_cpu->ap_list_lock);
> >> +}
> >> +
> >> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_process_maintenance(vcpu);
> >> +	else
> >> +		WARN(1, "GICv3 Not Implemented\n");
> >> +}
> >> +
> >> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_fold_lr_state(vcpu);
> >> +	else
> >> +		WARN(1, "GICv3 Not Implemented\n");
> >> +}
> >> +
> >> +/*
> >> + * Requires the ap_lock to be held.
> >> + * If irq is not NULL, requires the IRQ lock to be held as well.
> >> + * If irq is NULL, the list register gets cleared.
> >> + */
> >> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> >> +				    struct vgic_irq *irq, int lr)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_populate_lr(vcpu, irq, lr);
> >> +	else
> >> +		WARN(1, "GICv3 Not Implemented\n");
> >> +}
> >> +
> >> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_set_underflow(vcpu);
> >> +	else
> >> +		WARN(1, "GICv3 Not Implemented\n");
> >> +}
> >> +
> >> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> >> +	struct vgic_irq *irq;
> >> +	int count = 0;
> >> +
> >> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> >> +		spin_lock(&irq->irq_lock);
> >> +		/* GICv2 SGIs can count for more than one... */
> >> +		if (irq->intid < VGIC_NR_SGIS && irq->source)
> > 
> > how can we have an SGI on an AP list without the irq->source field set?
> > 
> > Is the irq->source check to cater for GICv3?
> 
> Yes, in the v3 case irq->source is 0, so the hweight is zero as well.
> 

ah right, missed that.

> >> +			count += hweight8(irq->source);
> >> +		else
> >> +			count++;
> >> +		spin_unlock(&irq->irq_lock);
> >> +	}
> >> +	return count;
> > 
> > this does feel like an awful lot of code on each entry.
> 
> Is this really a lot of code? I count two comparisons and an inc, or the
> hweight8 in case of SGIs. The latter implementation doesn't look to bad
> either (given that it all happens in a register).
> Or is there some code I missed?

The spin_lock inside the loop is what scared me, but you're right that
by far the common case is that the list is empty, so this is most likely
premature.

> 
> > I'm wondering
> > if we should have a count on each vgic_cpu containing the length of the
> > AP list which is then adjusted via the queue and removal functions?
> 
> That sounds like some work to make sure we cover all the cases. Also we
> would need to care about the consistency of this.

Not too scared of that, using an atomic counter and given that we have
the queue function, it's one place plus some MMIO handlers that need the
attention.  But yes, we can just fix that later if it makes a
difference, you can leave it for now.

> 
> >> +}
> >> +
> >> +/* requires the vcpu ap_lock to be held */
> > 
> > s/ap_lock/ap_list_lock/
> > 
> >> +static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
> > 
> > I'm not in love with the fact that we have two separate functions named:
> > 
> >   vgic_populate_lrs  and
> >   vgic_populate_lr
> > 
> > perhaps this could be changed to 'vgic_flush_ap_list' ?
> 
> Agreed.
> 
> > 
> >> +{
> >> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> >> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> >> +	struct vgic_irq *irq;
> >> +	int count = 0;
> >> +
> >> +	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
> >> +		vgic_set_underflow(vcpu);
> >> +		vgic_sort_ap_list(vcpu);
> >> +	}
> >> +
> >> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> >> +			goto next;
> >> +
> >> +		/*
> >> +		 * If we get an SGI with multiple sources, try to get
> >> +		 * them in all at once.
> >> +		 */
> >> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
> >> +		    irq->intid < VGIC_NR_SGIS) {
> > 
> > I wonder if a lot of this code would be more readable if we added and
> > used the following primitives:
> > vgic_irq_is_sgi()
> > vgic_irq_is_ppi()
> > vgic_irq_is_spi()
> 
> If that doesn't break 80 characters ... ;-)
> 

eh, it's already on its own line...

> >> +			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
> >> +				vgic_populate_lr(vcpu, irq, count++);
> >> +		} else {
> >> +			vgic_populate_lr(vcpu, irq, count++);
> >> +		}
> > 
> > this stuff about the SGIs is really dense, so I'm wondering if it's more
> > clean to make it even more dense and rewrite the whole if-statement to:
> > 
> > 	do {
> > 		vgic_populate(vcpu, irq, count++);
> > 	} while (irq->source && count < vgic.nr_lr);
> > 
> > (btw. I believe all these places referencing the nr_lr in the vgic_cpu
> > struct could use the global state structure instead).
> 
> Good point. We should convert all the places where this is easily doable
> already.
> 
> > 
> >> +
> >> +next:
> >> +		spin_unlock(&irq->irq_lock);
> >> +
> >> +		if (count == vcpu->arch.vgic_cpu.nr_lr)
> >> +			break;
> >> +	}
> >> +
> >> +	vcpu->arch.vgic_cpu.used_lrs = count;
> >> +
> >> +	/* Nuke remaining LRs */
> >> +	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
> >> +		vgic_populate_lr(vcpu, NULL, count);
> > 
> > should we not change this to adhere to the optimizations Marc
> > implemented for the current VGIC (i.e. clear the LRs on sync+init, and
> > only write what you need here)?
> 
> Those optimizations were not in the branch I based this series on.
> I will take a look with the new series being based on 4.6-rc (added
> live_lrs already).
> 

Thinking about this some more, probably we just want to respin the
series as it is currently, and then apply optimizations similar to what
we have for the legacy code on top of it.

Someone else than you could do that as well.

> 
> BTW: Thanks for the thorough review. I agree and will change all your
> comments I didn't explicitly replied on.
> 

Thanks for doing all the heavy lifting on this one!

-Christoffer

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

* Re: [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-04-06 14:09             ` Andre Przywara
@ 2016-04-06 14:46               ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-06 14:46 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Wed, Apr 06, 2016 at 03:09:50PM +0100, Andre Przywara wrote:
> 
> 
> On 06/04/16 14:57, Christoffer Dall wrote:
> > On Tue, Apr 05, 2016 at 10:10:09PM +0200, Christoffer Dall wrote:
> >> On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
> >>> Hi,
> >>>
> >>> On 29/03/16 14:09, Christoffer Dall wrote:
> >>>> On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
> >>>>> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>>>>
> >>>>> Add a new header file for the new and improved GIC implementation.
> >>>>> The big change is that we now have a struct vgic_irq per IRQ instead
> >>>>> of spreading all the information over various bitmaps.
> >>>>>
> >>>>> We include this new header conditionally from within the old header
> >>>>> file for the time being to avoid touching all the users.
> >>>>>
> >>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>>> ---
> >>>>>  include/kvm/arm_vgic.h  |   5 ++
> >>>>>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>>>>  2 files changed, 203 insertions(+)
> >>>>>  create mode 100644 include/kvm/vgic/vgic.h
> >>>>>
> >>>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> >>>>> index 7656a46..db289a2 100644
> >>>>> --- a/include/kvm/arm_vgic.h
> >>>>> +++ b/include/kvm/arm_vgic.h
> >>>>> @@ -19,6 +19,10 @@
> >>>>>  #ifndef __ASM_ARM_KVM_VGIC_H
> >>>>>  #define __ASM_ARM_KVM_VGIC_H
> >>>>>
> >>>>> +#ifdef CONFIG_KVM_NEW_VGIC
> >>>>> +#include <kvm/vgic/vgic.h>
> >>>>> +#else
> >>>>> +
> >>>>>  #include <linux/kernel.h>
> >>>>>  #include <linux/kvm.h>
> >>>>>  #include <linux/irqreturn.h>
> >>>>> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
> >>>>>  }
> >>>>>  #endif
> >>>>>
> >>>>> +#endif   /* old VGIC include */
> >>>>>  #endif
> >>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >>>>> new file mode 100644
> >>>>> index 0000000..659f8b1
> >>>>> --- /dev/null
> >>>>> +++ b/include/kvm/vgic/vgic.h
> >>>>> @@ -0,0 +1,198 @@
> >>>>> +/*
> >>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
> >>>>> + *
> >>>>> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
> >>>>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> >>>>> +
> >>>>> +#include <linux/kernel.h>
> >>>>> +#include <linux/kvm.h>
> >>>>> +#include <linux/irqreturn.h>
> >>>>> +#include <linux/spinlock.h>
> >>>>> +#include <linux/types.h>
> >>>>> +#include <kvm/iodev.h>
> >>>>> +
> >>>>> +#define VGIC_V3_MAX_CPUS 255
> >>>>> +#define VGIC_V2_MAX_CPUS 8
> >>>>> +#define VGIC_NR_IRQS_LEGACY     256
> >>>>> +#define VGIC_NR_SGIS             16
> >>>>> +#define VGIC_NR_PPIS             16
> >>>>> +#define VGIC_NR_PRIVATE_IRQS     (VGIC_NR_SGIS + VGIC_NR_PPIS)
> >>>>> +#define VGIC_MAX_PRIVATE (VGIC_NR_PRIVATE_IRQS - 1)
> >>>>> +#define VGIC_MAX_SPI             1019
> >>>>> +#define VGIC_MAX_RESERVED        1023
> >>>>> +#define VGIC_MIN_LPI             8192
> >>>>> +
> >>>>> +enum vgic_type {
> >>>>> + VGIC_V2,                /* Good ol' GICv2 */
> >>>>> + VGIC_V3,                /* New fancy GICv3 */
> >>>>> +};
> >>>>> +
> >>>>> +/* same for all guests, as depending only on the _host's_ GIC model */
> >>>>> +struct vgic_global {
> >>>>> + /* type of the host GIC */
> >>>>> + enum vgic_type          type;
> >>>>> +
> >>>>> + /* Physical address of vgic virtual cpu interface */
> >>>>> + phys_addr_t             vcpu_base;
> >>>>> +
> >>>>> + /* virtual control interface mapping */
> >>>>> + void __iomem            *vctrl_base;
> >>>>> +
> >>>>> + /* Number of implemented list registers */
> >>>>> + int                     nr_lr;
> >>>>> +
> >>>>> + /* Maintenance IRQ number */
> >>>>> + unsigned int            maint_irq;
> >>>>> +
> >>>>> + /* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> >>>>> + int                     max_gic_vcpus;
> >>>>> +
> >>>>> + /* Only needed for the legacy KVM_CREATE_IRQCHIP */
> >>>>> + bool                    can_emulate_gicv2;
> >>>>> +};
> >>>>> +
> >>>>> +extern struct vgic_global kvm_vgic_global_state;
> >>>>> +
> >>>>> +#define VGIC_V2_MAX_LRS          (1 << 6)
> >>>>> +#define VGIC_V3_MAX_LRS          16
> >>>>> +#define VGIC_V3_LR_INDEX(lr)     (VGIC_V3_MAX_LRS - 1 - lr)
> >>>>> +
> >>>>> +enum vgic_irq_config {
> >>>>> + VGIC_CONFIG_EDGE = 0,
> >>>>> + VGIC_CONFIG_LEVEL
> >>>>> +};
> >>>>> +
> >>>>> +struct vgic_irq {
> >>>>> + spinlock_t irq_lock;            /* Protects the content of the struct */
> >>>>> + struct list_head ap_list;
> >>>>> +
> >>>>> + struct kvm_vcpu *vcpu;          /* SGIs and PPIs: The VCPU
> >>>>> +                                  * SPIs and LPIs: The VCPU whose ap_list
> >>>>> +                                  * on which this is queued.
> >>>>> +                                  */
> >>>>> +
> >>>>> + struct kvm_vcpu *target_vcpu;   /* The VCPU that this interrupt should
> >>>>> +                                  * be send to, as a result of the
> >>>>> +                                  * targets reg (v2) or the
> >>>>> +                                  * affinity reg (v3).
> >>>>> +                                  */
> >>>>> +
> >>>>> + u32 intid;                      /* Guest visible INTID */
> >>>>> + bool pending;
> >>>>> + bool line_level;                /* Level only */
> >>>>> + bool soft_pending;              /* Level only */
> >>>>> + bool active;                    /* not used for LPIs */
> >>>>> + bool enabled;
> >>>>> + bool hw;                        /* Tied to HW IRQ */
> >>>>> + u32 hwintid;                    /* HW INTID number */
> >>>>> + union {
> >>>>> +         u8 targets;                     /* GICv2 target VCPUs mask */
> >>>>> +         u32 mpidr;                      /* GICv3 target VCPU */
> >>>>> + };
> >>>>> + u8 source;                      /* GICv2 SGIs only */
> >>>>> + u8 priority;
> >>>>> + enum vgic_irq_config config;    /* Level or edge */
> >>>>> +};
> >>>>> +
> >>>>> +struct vgic_dist {
> >>>>> + bool                    in_kernel;
> >>>>> + bool                    ready;
> >>>>> +
> >>>>> + /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> >>>>> + u32                     vgic_model;
> >>>>> +
> >>>>> + int                     nr_spis;
> >>>>> +
> >>>>> + /* TODO: Consider moving to global state */
> >>>>> + /* Virtual control interface mapping */
> >>>>> + void __iomem            *vctrl_base;
> >>>>> +
> >>>>> + /* base addresses in guest physical address space: */
> >>>>> + gpa_t                   vgic_dist_base;         /* distributor */
> >>>>> + union {
> >>>>> +         /* either a GICv2 CPU interface */
> >>>>> +         gpa_t                   vgic_cpu_base;
> >>>>> +         /* or a number of GICv3 redistributor regions */
> >>>>> +         gpa_t                   vgic_redist_base;
> >>>>> + };
> >>>>> +
> >>>>> + /* distributor enabled */
> >>>>> + u32                     enabled;
> >>>>> +
> >>>>> + struct vgic_irq         *spis;
> >>>>> +};
> >>>>> +
> >>>>> +struct vgic_v2_cpu_if {
> >>>>> + u32             vgic_hcr;
> >>>>> + u32             vgic_vmcr;
> >>>>> + u32             vgic_misr;      /* Saved only */
> >>>>> + u64             vgic_eisr;      /* Saved only */
> >>>>> + u64             vgic_elrsr;     /* Saved only */
> >>>>> + u32             vgic_apr;
> >>>>> + u32             vgic_lr[VGIC_V2_MAX_LRS];
> >>>>> +};
> >>>>> +
> >>>>> +struct vgic_v3_cpu_if {
> >>>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> >>>>> + u32             vgic_hcr;
> >>>>> + u32             vgic_vmcr;
> >>>>> + u32             vgic_sre;       /* Restored only, change ignored */
> >>>>> + u32             vgic_misr;      /* Saved only */
> >>>>> + u32             vgic_eisr;      /* Saved only */
> >>>>> + u32             vgic_elrsr;     /* Saved only */
> >>>>> + u32             vgic_ap0r[4];
> >>>>> + u32             vgic_ap1r[4];
> >>>>> + u64             vgic_lr[VGIC_V3_MAX_LRS];
> >>>>> +#endif
> >>>>> +};
> >>>>> +
> >>>>> +struct vgic_cpu {
> >>>>> + /* CPU vif control registers for world switch */
> >>>>> + union {
> >>>>> +         struct vgic_v2_cpu_if   vgic_v2;
> >>>>> +         struct vgic_v3_cpu_if   vgic_v3;
> >>>>> + };
> >>>>> +
> >>>>> + /* TODO: Move nr_lr to a global state */
> >>>>
> >>>> what is our current plan and status about this TODO?
> >>>
> >>> The point is that the current HYP code is accessing this field. We do
> >>> have this field in the current "global" struct vgic_params there as
> >>> well, but this struct is (more or less) private to vgic-v2.c, so not
> >>> easily accessible from virt/kvm/arm/hyp/*.c.
> >>> So I suggest we keep this in here for the time being and eventually
> >>> remove it (and rework the save/restore code) once we get rid of the old
> >>> VGIC code.
> >>>
> >> Hmmm, I haven't tried it, but I don't understand why moving it now is
> >> difficult.  I'd really like to avoid having a bunch of todo's lingering
> >> around and having duplicated state in the new code.
> >>
> >> I think I noticed a number of places in this patch series which refers
> >> tot he vgic_cpu->nr_lr instead of the global place already...
> >>
> > So I wrote a patch for this and it doesn't really look that bad.  I'll
> > send it as part of a little prerequisite series later.
> 
> I just fixed it as well - the private new VGIC part is trivial indeed.
> But how did you solve the reference to the vgic_cpu.nr_lr in
> virt/kvm/arm/hyp/vgic-v2-sr.c? With #ifdef .. #else? Or passing in the
> number as in vgic-v3-sr.c?
> 

I sent you a couple of patches as I said I would.

I just used an extern with the kern_hyp_va() macro trickery applied.
Not the prettiest thing in the world, but hey.  It should serve just
fine for moving on with this, and then we can worry about the finesses
as the vgic series progresses.

-Christoffer

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

* [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-04-06 14:46               ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-06 14:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 06, 2016 at 03:09:50PM +0100, Andre Przywara wrote:
> 
> 
> On 06/04/16 14:57, Christoffer Dall wrote:
> > On Tue, Apr 05, 2016 at 10:10:09PM +0200, Christoffer Dall wrote:
> >> On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
> >>> Hi,
> >>>
> >>> On 29/03/16 14:09, Christoffer Dall wrote:
> >>>> On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
> >>>>> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>>>>
> >>>>> Add a new header file for the new and improved GIC implementation.
> >>>>> The big change is that we now have a struct vgic_irq per IRQ instead
> >>>>> of spreading all the information over various bitmaps.
> >>>>>
> >>>>> We include this new header conditionally from within the old header
> >>>>> file for the time being to avoid touching all the users.
> >>>>>
> >>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>>> ---
> >>>>>  include/kvm/arm_vgic.h  |   5 ++
> >>>>>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>>>>  2 files changed, 203 insertions(+)
> >>>>>  create mode 100644 include/kvm/vgic/vgic.h
> >>>>>
> >>>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> >>>>> index 7656a46..db289a2 100644
> >>>>> --- a/include/kvm/arm_vgic.h
> >>>>> +++ b/include/kvm/arm_vgic.h
> >>>>> @@ -19,6 +19,10 @@
> >>>>>  #ifndef __ASM_ARM_KVM_VGIC_H
> >>>>>  #define __ASM_ARM_KVM_VGIC_H
> >>>>>
> >>>>> +#ifdef CONFIG_KVM_NEW_VGIC
> >>>>> +#include <kvm/vgic/vgic.h>
> >>>>> +#else
> >>>>> +
> >>>>>  #include <linux/kernel.h>
> >>>>>  #include <linux/kvm.h>
> >>>>>  #include <linux/irqreturn.h>
> >>>>> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
> >>>>>  }
> >>>>>  #endif
> >>>>>
> >>>>> +#endif   /* old VGIC include */
> >>>>>  #endif
> >>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >>>>> new file mode 100644
> >>>>> index 0000000..659f8b1
> >>>>> --- /dev/null
> >>>>> +++ b/include/kvm/vgic/vgic.h
> >>>>> @@ -0,0 +1,198 @@
> >>>>> +/*
> >>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
> >>>>> + *
> >>>>> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
> >>>>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> >>>>> +
> >>>>> +#include <linux/kernel.h>
> >>>>> +#include <linux/kvm.h>
> >>>>> +#include <linux/irqreturn.h>
> >>>>> +#include <linux/spinlock.h>
> >>>>> +#include <linux/types.h>
> >>>>> +#include <kvm/iodev.h>
> >>>>> +
> >>>>> +#define VGIC_V3_MAX_CPUS 255
> >>>>> +#define VGIC_V2_MAX_CPUS 8
> >>>>> +#define VGIC_NR_IRQS_LEGACY     256
> >>>>> +#define VGIC_NR_SGIS             16
> >>>>> +#define VGIC_NR_PPIS             16
> >>>>> +#define VGIC_NR_PRIVATE_IRQS     (VGIC_NR_SGIS + VGIC_NR_PPIS)
> >>>>> +#define VGIC_MAX_PRIVATE (VGIC_NR_PRIVATE_IRQS - 1)
> >>>>> +#define VGIC_MAX_SPI             1019
> >>>>> +#define VGIC_MAX_RESERVED        1023
> >>>>> +#define VGIC_MIN_LPI             8192
> >>>>> +
> >>>>> +enum vgic_type {
> >>>>> + VGIC_V2,                /* Good ol' GICv2 */
> >>>>> + VGIC_V3,                /* New fancy GICv3 */
> >>>>> +};
> >>>>> +
> >>>>> +/* same for all guests, as depending only on the _host's_ GIC model */
> >>>>> +struct vgic_global {
> >>>>> + /* type of the host GIC */
> >>>>> + enum vgic_type          type;
> >>>>> +
> >>>>> + /* Physical address of vgic virtual cpu interface */
> >>>>> + phys_addr_t             vcpu_base;
> >>>>> +
> >>>>> + /* virtual control interface mapping */
> >>>>> + void __iomem            *vctrl_base;
> >>>>> +
> >>>>> + /* Number of implemented list registers */
> >>>>> + int                     nr_lr;
> >>>>> +
> >>>>> + /* Maintenance IRQ number */
> >>>>> + unsigned int            maint_irq;
> >>>>> +
> >>>>> + /* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> >>>>> + int                     max_gic_vcpus;
> >>>>> +
> >>>>> + /* Only needed for the legacy KVM_CREATE_IRQCHIP */
> >>>>> + bool                    can_emulate_gicv2;
> >>>>> +};
> >>>>> +
> >>>>> +extern struct vgic_global kvm_vgic_global_state;
> >>>>> +
> >>>>> +#define VGIC_V2_MAX_LRS          (1 << 6)
> >>>>> +#define VGIC_V3_MAX_LRS          16
> >>>>> +#define VGIC_V3_LR_INDEX(lr)     (VGIC_V3_MAX_LRS - 1 - lr)
> >>>>> +
> >>>>> +enum vgic_irq_config {
> >>>>> + VGIC_CONFIG_EDGE = 0,
> >>>>> + VGIC_CONFIG_LEVEL
> >>>>> +};
> >>>>> +
> >>>>> +struct vgic_irq {
> >>>>> + spinlock_t irq_lock;            /* Protects the content of the struct */
> >>>>> + struct list_head ap_list;
> >>>>> +
> >>>>> + struct kvm_vcpu *vcpu;          /* SGIs and PPIs: The VCPU
> >>>>> +                                  * SPIs and LPIs: The VCPU whose ap_list
> >>>>> +                                  * on which this is queued.
> >>>>> +                                  */
> >>>>> +
> >>>>> + struct kvm_vcpu *target_vcpu;   /* The VCPU that this interrupt should
> >>>>> +                                  * be send to, as a result of the
> >>>>> +                                  * targets reg (v2) or the
> >>>>> +                                  * affinity reg (v3).
> >>>>> +                                  */
> >>>>> +
> >>>>> + u32 intid;                      /* Guest visible INTID */
> >>>>> + bool pending;
> >>>>> + bool line_level;                /* Level only */
> >>>>> + bool soft_pending;              /* Level only */
> >>>>> + bool active;                    /* not used for LPIs */
> >>>>> + bool enabled;
> >>>>> + bool hw;                        /* Tied to HW IRQ */
> >>>>> + u32 hwintid;                    /* HW INTID number */
> >>>>> + union {
> >>>>> +         u8 targets;                     /* GICv2 target VCPUs mask */
> >>>>> +         u32 mpidr;                      /* GICv3 target VCPU */
> >>>>> + };
> >>>>> + u8 source;                      /* GICv2 SGIs only */
> >>>>> + u8 priority;
> >>>>> + enum vgic_irq_config config;    /* Level or edge */
> >>>>> +};
> >>>>> +
> >>>>> +struct vgic_dist {
> >>>>> + bool                    in_kernel;
> >>>>> + bool                    ready;
> >>>>> +
> >>>>> + /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> >>>>> + u32                     vgic_model;
> >>>>> +
> >>>>> + int                     nr_spis;
> >>>>> +
> >>>>> + /* TODO: Consider moving to global state */
> >>>>> + /* Virtual control interface mapping */
> >>>>> + void __iomem            *vctrl_base;
> >>>>> +
> >>>>> + /* base addresses in guest physical address space: */
> >>>>> + gpa_t                   vgic_dist_base;         /* distributor */
> >>>>> + union {
> >>>>> +         /* either a GICv2 CPU interface */
> >>>>> +         gpa_t                   vgic_cpu_base;
> >>>>> +         /* or a number of GICv3 redistributor regions */
> >>>>> +         gpa_t                   vgic_redist_base;
> >>>>> + };
> >>>>> +
> >>>>> + /* distributor enabled */
> >>>>> + u32                     enabled;
> >>>>> +
> >>>>> + struct vgic_irq         *spis;
> >>>>> +};
> >>>>> +
> >>>>> +struct vgic_v2_cpu_if {
> >>>>> + u32             vgic_hcr;
> >>>>> + u32             vgic_vmcr;
> >>>>> + u32             vgic_misr;      /* Saved only */
> >>>>> + u64             vgic_eisr;      /* Saved only */
> >>>>> + u64             vgic_elrsr;     /* Saved only */
> >>>>> + u32             vgic_apr;
> >>>>> + u32             vgic_lr[VGIC_V2_MAX_LRS];
> >>>>> +};
> >>>>> +
> >>>>> +struct vgic_v3_cpu_if {
> >>>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> >>>>> + u32             vgic_hcr;
> >>>>> + u32             vgic_vmcr;
> >>>>> + u32             vgic_sre;       /* Restored only, change ignored */
> >>>>> + u32             vgic_misr;      /* Saved only */
> >>>>> + u32             vgic_eisr;      /* Saved only */
> >>>>> + u32             vgic_elrsr;     /* Saved only */
> >>>>> + u32             vgic_ap0r[4];
> >>>>> + u32             vgic_ap1r[4];
> >>>>> + u64             vgic_lr[VGIC_V3_MAX_LRS];
> >>>>> +#endif
> >>>>> +};
> >>>>> +
> >>>>> +struct vgic_cpu {
> >>>>> + /* CPU vif control registers for world switch */
> >>>>> + union {
> >>>>> +         struct vgic_v2_cpu_if   vgic_v2;
> >>>>> +         struct vgic_v3_cpu_if   vgic_v3;
> >>>>> + };
> >>>>> +
> >>>>> + /* TODO: Move nr_lr to a global state */
> >>>>
> >>>> what is our current plan and status about this TODO?
> >>>
> >>> The point is that the current HYP code is accessing this field. We do
> >>> have this field in the current "global" struct vgic_params there as
> >>> well, but this struct is (more or less) private to vgic-v2.c, so not
> >>> easily accessible from virt/kvm/arm/hyp/*.c.
> >>> So I suggest we keep this in here for the time being and eventually
> >>> remove it (and rework the save/restore code) once we get rid of the old
> >>> VGIC code.
> >>>
> >> Hmmm, I haven't tried it, but I don't understand why moving it now is
> >> difficult.  I'd really like to avoid having a bunch of todo's lingering
> >> around and having duplicated state in the new code.
> >>
> >> I think I noticed a number of places in this patch series which refers
> >> tot he vgic_cpu->nr_lr instead of the global place already...
> >>
> > So I wrote a patch for this and it doesn't really look that bad.  I'll
> > send it as part of a little prerequisite series later.
> 
> I just fixed it as well - the private new VGIC part is trivial indeed.
> But how did you solve the reference to the vgic_cpu.nr_lr in
> virt/kvm/arm/hyp/vgic-v2-sr.c? With #ifdef .. #else? Or passing in the
> number as in vgic-v3-sr.c?
> 

I sent you a couple of patches as I said I would.

I just used an extern with the kern_hyp_va() macro trickery applied.
Not the prettiest thing in the world, but hey.  It should serve just
fine for moving on with this, and then we can worry about the finesses
as the vgic series progresses.

-Christoffer

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

* Re: [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-04-06 14:46               ` Christoffer Dall
@ 2016-04-06 14:53                 ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-06 14:53 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hej Christoffer,

On 06/04/16 15:46, Christoffer Dall wrote:
> On Wed, Apr 06, 2016 at 03:09:50PM +0100, Andre Przywara wrote:
>>
>>
>> On 06/04/16 14:57, Christoffer Dall wrote:
>>> On Tue, Apr 05, 2016 at 10:10:09PM +0200, Christoffer Dall wrote:
>>>> On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
>>>>> Hi,
>>>>>
>>>>> On 29/03/16 14:09, Christoffer Dall wrote:
>>>>>> On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
>>>>>>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>>>>>>
>>>>>>> Add a new header file for the new and improved GIC implementation.
>>>>>>> The big change is that we now have a struct vgic_irq per IRQ instead
>>>>>>> of spreading all the information over various bitmaps.
>>>>>>>
>>>>>>> We include this new header conditionally from within the old header
>>>>>>> file for the time being to avoid touching all the users.
>>>>>>>
>>>>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>>>> ---
>>>>>>>  include/kvm/arm_vgic.h  |   5 ++
>>>>>>>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>  2 files changed, 203 insertions(+)
>>>>>>>  create mode 100644 include/kvm/vgic/vgic.h
>>>>>>>
>>>>>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>>>>>> index 7656a46..db289a2 100644
>>>>>>> --- a/include/kvm/arm_vgic.h
>>>>>>> +++ b/include/kvm/arm_vgic.h
>>>>>>> @@ -19,6 +19,10 @@
>>>>>>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>>>>>>  #define __ASM_ARM_KVM_VGIC_H
>>>>>>>
>>>>>>> +#ifdef CONFIG_KVM_NEW_VGIC
>>>>>>> +#include <kvm/vgic/vgic.h>
>>>>>>> +#else
>>>>>>> +
>>>>>>>  #include <linux/kernel.h>
>>>>>>>  #include <linux/kvm.h>
>>>>>>>  #include <linux/irqreturn.h>
>>>>>>> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>>>>>>  }
>>>>>>>  #endif
>>>>>>>
>>>>>>> +#endif   /* old VGIC include */
>>>>>>>  #endif
>>>>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>>>>>>> new file mode 100644
>>>>>>> index 0000000..659f8b1
>>>>>>> --- /dev/null
>>>>>>> +++ b/include/kvm/vgic/vgic.h
>>>>>>> @@ -0,0 +1,198 @@
>>>>>>> +/*
>>>>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>>>>> + *
>>>>>>> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
>>>>>>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>>>>>>> +
>>>>>>> +#include <linux/kernel.h>
>>>>>>> +#include <linux/kvm.h>
>>>>>>> +#include <linux/irqreturn.h>
>>>>>>> +#include <linux/spinlock.h>
>>>>>>> +#include <linux/types.h>
>>>>>>> +#include <kvm/iodev.h>
>>>>>>> +
>>>>>>> +#define VGIC_V3_MAX_CPUS 255
>>>>>>> +#define VGIC_V2_MAX_CPUS 8
>>>>>>> +#define VGIC_NR_IRQS_LEGACY     256
>>>>>>> +#define VGIC_NR_SGIS             16
>>>>>>> +#define VGIC_NR_PPIS             16
>>>>>>> +#define VGIC_NR_PRIVATE_IRQS     (VGIC_NR_SGIS + VGIC_NR_PPIS)
>>>>>>> +#define VGIC_MAX_PRIVATE (VGIC_NR_PRIVATE_IRQS - 1)
>>>>>>> +#define VGIC_MAX_SPI             1019
>>>>>>> +#define VGIC_MAX_RESERVED        1023
>>>>>>> +#define VGIC_MIN_LPI             8192
>>>>>>> +
>>>>>>> +enum vgic_type {
>>>>>>> + VGIC_V2,                /* Good ol' GICv2 */
>>>>>>> + VGIC_V3,                /* New fancy GICv3 */
>>>>>>> +};
>>>>>>> +
>>>>>>> +/* same for all guests, as depending only on the _host's_ GIC model */
>>>>>>> +struct vgic_global {
>>>>>>> + /* type of the host GIC */
>>>>>>> + enum vgic_type          type;
>>>>>>> +
>>>>>>> + /* Physical address of vgic virtual cpu interface */
>>>>>>> + phys_addr_t             vcpu_base;
>>>>>>> +
>>>>>>> + /* virtual control interface mapping */
>>>>>>> + void __iomem            *vctrl_base;
>>>>>>> +
>>>>>>> + /* Number of implemented list registers */
>>>>>>> + int                     nr_lr;
>>>>>>> +
>>>>>>> + /* Maintenance IRQ number */
>>>>>>> + unsigned int            maint_irq;
>>>>>>> +
>>>>>>> + /* maximum number of VCPUs allowed (GICv2 limits us to 8) */
>>>>>>> + int                     max_gic_vcpus;
>>>>>>> +
>>>>>>> + /* Only needed for the legacy KVM_CREATE_IRQCHIP */
>>>>>>> + bool                    can_emulate_gicv2;
>>>>>>> +};
>>>>>>> +
>>>>>>> +extern struct vgic_global kvm_vgic_global_state;
>>>>>>> +
>>>>>>> +#define VGIC_V2_MAX_LRS          (1 << 6)
>>>>>>> +#define VGIC_V3_MAX_LRS          16
>>>>>>> +#define VGIC_V3_LR_INDEX(lr)     (VGIC_V3_MAX_LRS - 1 - lr)
>>>>>>> +
>>>>>>> +enum vgic_irq_config {
>>>>>>> + VGIC_CONFIG_EDGE = 0,
>>>>>>> + VGIC_CONFIG_LEVEL
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct vgic_irq {
>>>>>>> + spinlock_t irq_lock;            /* Protects the content of the struct */
>>>>>>> + struct list_head ap_list;
>>>>>>> +
>>>>>>> + struct kvm_vcpu *vcpu;          /* SGIs and PPIs: The VCPU
>>>>>>> +                                  * SPIs and LPIs: The VCPU whose ap_list
>>>>>>> +                                  * on which this is queued.
>>>>>>> +                                  */
>>>>>>> +
>>>>>>> + struct kvm_vcpu *target_vcpu;   /* The VCPU that this interrupt should
>>>>>>> +                                  * be send to, as a result of the
>>>>>>> +                                  * targets reg (v2) or the
>>>>>>> +                                  * affinity reg (v3).
>>>>>>> +                                  */
>>>>>>> +
>>>>>>> + u32 intid;                      /* Guest visible INTID */
>>>>>>> + bool pending;
>>>>>>> + bool line_level;                /* Level only */
>>>>>>> + bool soft_pending;              /* Level only */
>>>>>>> + bool active;                    /* not used for LPIs */
>>>>>>> + bool enabled;
>>>>>>> + bool hw;                        /* Tied to HW IRQ */
>>>>>>> + u32 hwintid;                    /* HW INTID number */
>>>>>>> + union {
>>>>>>> +         u8 targets;                     /* GICv2 target VCPUs mask */
>>>>>>> +         u32 mpidr;                      /* GICv3 target VCPU */
>>>>>>> + };
>>>>>>> + u8 source;                      /* GICv2 SGIs only */
>>>>>>> + u8 priority;
>>>>>>> + enum vgic_irq_config config;    /* Level or edge */
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct vgic_dist {
>>>>>>> + bool                    in_kernel;
>>>>>>> + bool                    ready;
>>>>>>> +
>>>>>>> + /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>>>>>>> + u32                     vgic_model;
>>>>>>> +
>>>>>>> + int                     nr_spis;
>>>>>>> +
>>>>>>> + /* TODO: Consider moving to global state */
>>>>>>> + /* Virtual control interface mapping */
>>>>>>> + void __iomem            *vctrl_base;
>>>>>>> +
>>>>>>> + /* base addresses in guest physical address space: */
>>>>>>> + gpa_t                   vgic_dist_base;         /* distributor */
>>>>>>> + union {
>>>>>>> +         /* either a GICv2 CPU interface */
>>>>>>> +         gpa_t                   vgic_cpu_base;
>>>>>>> +         /* or a number of GICv3 redistributor regions */
>>>>>>> +         gpa_t                   vgic_redist_base;
>>>>>>> + };
>>>>>>> +
>>>>>>> + /* distributor enabled */
>>>>>>> + u32                     enabled;
>>>>>>> +
>>>>>>> + struct vgic_irq         *spis;
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct vgic_v2_cpu_if {
>>>>>>> + u32             vgic_hcr;
>>>>>>> + u32             vgic_vmcr;
>>>>>>> + u32             vgic_misr;      /* Saved only */
>>>>>>> + u64             vgic_eisr;      /* Saved only */
>>>>>>> + u64             vgic_elrsr;     /* Saved only */
>>>>>>> + u32             vgic_apr;
>>>>>>> + u32             vgic_lr[VGIC_V2_MAX_LRS];
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct vgic_v3_cpu_if {
>>>>>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>>>>>>> + u32             vgic_hcr;
>>>>>>> + u32             vgic_vmcr;
>>>>>>> + u32             vgic_sre;       /* Restored only, change ignored */
>>>>>>> + u32             vgic_misr;      /* Saved only */
>>>>>>> + u32             vgic_eisr;      /* Saved only */
>>>>>>> + u32             vgic_elrsr;     /* Saved only */
>>>>>>> + u32             vgic_ap0r[4];
>>>>>>> + u32             vgic_ap1r[4];
>>>>>>> + u64             vgic_lr[VGIC_V3_MAX_LRS];
>>>>>>> +#endif
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct vgic_cpu {
>>>>>>> + /* CPU vif control registers for world switch */
>>>>>>> + union {
>>>>>>> +         struct vgic_v2_cpu_if   vgic_v2;
>>>>>>> +         struct vgic_v3_cpu_if   vgic_v3;
>>>>>>> + };
>>>>>>> +
>>>>>>> + /* TODO: Move nr_lr to a global state */
>>>>>>
>>>>>> what is our current plan and status about this TODO?
>>>>>
>>>>> The point is that the current HYP code is accessing this field. We do
>>>>> have this field in the current "global" struct vgic_params there as
>>>>> well, but this struct is (more or less) private to vgic-v2.c, so not
>>>>> easily accessible from virt/kvm/arm/hyp/*.c.
>>>>> So I suggest we keep this in here for the time being and eventually
>>>>> remove it (and rework the save/restore code) once we get rid of the old
>>>>> VGIC code.
>>>>>
>>>> Hmmm, I haven't tried it, but I don't understand why moving it now is
>>>> difficult.  I'd really like to avoid having a bunch of todo's lingering
>>>> around and having duplicated state in the new code.
>>>>
>>>> I think I noticed a number of places in this patch series which refers
>>>> tot he vgic_cpu->nr_lr instead of the global place already...
>>>>
>>> So I wrote a patch for this and it doesn't really look that bad.  I'll
>>> send it as part of a little prerequisite series later.
>>
>> I just fixed it as well - the private new VGIC part is trivial indeed.
>> But how did you solve the reference to the vgic_cpu.nr_lr in
>> virt/kvm/arm/hyp/vgic-v2-sr.c? With #ifdef .. #else? Or passing in the
>> number as in vgic-v3-sr.c?
>>
> 
> I sent you a couple of patches as I said I would.
> 
> I just used an extern with the kern_hyp_va() macro trickery applied.
> Not the prettiest thing in the world, but hey.  It should serve just
> fine for moving on with this, and then we can worry about the finesses
> as the vgic series progresses.

Agreed, thanks for those patches. I think I will just cherry-pick 2/3
and 3/3.
I am tempted to post my version of what you did in 1/3, which goes a bit
further and avoids some copying between different kind of structs.

Cheers,
Andre.

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

* [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-04-06 14:53                 ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-06 14:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hej Christoffer,

On 06/04/16 15:46, Christoffer Dall wrote:
> On Wed, Apr 06, 2016 at 03:09:50PM +0100, Andre Przywara wrote:
>>
>>
>> On 06/04/16 14:57, Christoffer Dall wrote:
>>> On Tue, Apr 05, 2016 at 10:10:09PM +0200, Christoffer Dall wrote:
>>>> On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
>>>>> Hi,
>>>>>
>>>>> On 29/03/16 14:09, Christoffer Dall wrote:
>>>>>> On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
>>>>>>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>>>>>>
>>>>>>> Add a new header file for the new and improved GIC implementation.
>>>>>>> The big change is that we now have a struct vgic_irq per IRQ instead
>>>>>>> of spreading all the information over various bitmaps.
>>>>>>>
>>>>>>> We include this new header conditionally from within the old header
>>>>>>> file for the time being to avoid touching all the users.
>>>>>>>
>>>>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>>>> ---
>>>>>>>  include/kvm/arm_vgic.h  |   5 ++
>>>>>>>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>  2 files changed, 203 insertions(+)
>>>>>>>  create mode 100644 include/kvm/vgic/vgic.h
>>>>>>>
>>>>>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>>>>>> index 7656a46..db289a2 100644
>>>>>>> --- a/include/kvm/arm_vgic.h
>>>>>>> +++ b/include/kvm/arm_vgic.h
>>>>>>> @@ -19,6 +19,10 @@
>>>>>>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>>>>>>  #define __ASM_ARM_KVM_VGIC_H
>>>>>>>
>>>>>>> +#ifdef CONFIG_KVM_NEW_VGIC
>>>>>>> +#include <kvm/vgic/vgic.h>
>>>>>>> +#else
>>>>>>> +
>>>>>>>  #include <linux/kernel.h>
>>>>>>>  #include <linux/kvm.h>
>>>>>>>  #include <linux/irqreturn.h>
>>>>>>> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>>>>>>  }
>>>>>>>  #endif
>>>>>>>
>>>>>>> +#endif   /* old VGIC include */
>>>>>>>  #endif
>>>>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>>>>>>> new file mode 100644
>>>>>>> index 0000000..659f8b1
>>>>>>> --- /dev/null
>>>>>>> +++ b/include/kvm/vgic/vgic.h
>>>>>>> @@ -0,0 +1,198 @@
>>>>>>> +/*
>>>>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>>>>> + *
>>>>>>> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
>>>>>>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>>>>>>> +
>>>>>>> +#include <linux/kernel.h>
>>>>>>> +#include <linux/kvm.h>
>>>>>>> +#include <linux/irqreturn.h>
>>>>>>> +#include <linux/spinlock.h>
>>>>>>> +#include <linux/types.h>
>>>>>>> +#include <kvm/iodev.h>
>>>>>>> +
>>>>>>> +#define VGIC_V3_MAX_CPUS 255
>>>>>>> +#define VGIC_V2_MAX_CPUS 8
>>>>>>> +#define VGIC_NR_IRQS_LEGACY     256
>>>>>>> +#define VGIC_NR_SGIS             16
>>>>>>> +#define VGIC_NR_PPIS             16
>>>>>>> +#define VGIC_NR_PRIVATE_IRQS     (VGIC_NR_SGIS + VGIC_NR_PPIS)
>>>>>>> +#define VGIC_MAX_PRIVATE (VGIC_NR_PRIVATE_IRQS - 1)
>>>>>>> +#define VGIC_MAX_SPI             1019
>>>>>>> +#define VGIC_MAX_RESERVED        1023
>>>>>>> +#define VGIC_MIN_LPI             8192
>>>>>>> +
>>>>>>> +enum vgic_type {
>>>>>>> + VGIC_V2,                /* Good ol' GICv2 */
>>>>>>> + VGIC_V3,                /* New fancy GICv3 */
>>>>>>> +};
>>>>>>> +
>>>>>>> +/* same for all guests, as depending only on the _host's_ GIC model */
>>>>>>> +struct vgic_global {
>>>>>>> + /* type of the host GIC */
>>>>>>> + enum vgic_type          type;
>>>>>>> +
>>>>>>> + /* Physical address of vgic virtual cpu interface */
>>>>>>> + phys_addr_t             vcpu_base;
>>>>>>> +
>>>>>>> + /* virtual control interface mapping */
>>>>>>> + void __iomem            *vctrl_base;
>>>>>>> +
>>>>>>> + /* Number of implemented list registers */
>>>>>>> + int                     nr_lr;
>>>>>>> +
>>>>>>> + /* Maintenance IRQ number */
>>>>>>> + unsigned int            maint_irq;
>>>>>>> +
>>>>>>> + /* maximum number of VCPUs allowed (GICv2 limits us to 8) */
>>>>>>> + int                     max_gic_vcpus;
>>>>>>> +
>>>>>>> + /* Only needed for the legacy KVM_CREATE_IRQCHIP */
>>>>>>> + bool                    can_emulate_gicv2;
>>>>>>> +};
>>>>>>> +
>>>>>>> +extern struct vgic_global kvm_vgic_global_state;
>>>>>>> +
>>>>>>> +#define VGIC_V2_MAX_LRS          (1 << 6)
>>>>>>> +#define VGIC_V3_MAX_LRS          16
>>>>>>> +#define VGIC_V3_LR_INDEX(lr)     (VGIC_V3_MAX_LRS - 1 - lr)
>>>>>>> +
>>>>>>> +enum vgic_irq_config {
>>>>>>> + VGIC_CONFIG_EDGE = 0,
>>>>>>> + VGIC_CONFIG_LEVEL
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct vgic_irq {
>>>>>>> + spinlock_t irq_lock;            /* Protects the content of the struct */
>>>>>>> + struct list_head ap_list;
>>>>>>> +
>>>>>>> + struct kvm_vcpu *vcpu;          /* SGIs and PPIs: The VCPU
>>>>>>> +                                  * SPIs and LPIs: The VCPU whose ap_list
>>>>>>> +                                  * on which this is queued.
>>>>>>> +                                  */
>>>>>>> +
>>>>>>> + struct kvm_vcpu *target_vcpu;   /* The VCPU that this interrupt should
>>>>>>> +                                  * be send to, as a result of the
>>>>>>> +                                  * targets reg (v2) or the
>>>>>>> +                                  * affinity reg (v3).
>>>>>>> +                                  */
>>>>>>> +
>>>>>>> + u32 intid;                      /* Guest visible INTID */
>>>>>>> + bool pending;
>>>>>>> + bool line_level;                /* Level only */
>>>>>>> + bool soft_pending;              /* Level only */
>>>>>>> + bool active;                    /* not used for LPIs */
>>>>>>> + bool enabled;
>>>>>>> + bool hw;                        /* Tied to HW IRQ */
>>>>>>> + u32 hwintid;                    /* HW INTID number */
>>>>>>> + union {
>>>>>>> +         u8 targets;                     /* GICv2 target VCPUs mask */
>>>>>>> +         u32 mpidr;                      /* GICv3 target VCPU */
>>>>>>> + };
>>>>>>> + u8 source;                      /* GICv2 SGIs only */
>>>>>>> + u8 priority;
>>>>>>> + enum vgic_irq_config config;    /* Level or edge */
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct vgic_dist {
>>>>>>> + bool                    in_kernel;
>>>>>>> + bool                    ready;
>>>>>>> +
>>>>>>> + /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>>>>>>> + u32                     vgic_model;
>>>>>>> +
>>>>>>> + int                     nr_spis;
>>>>>>> +
>>>>>>> + /* TODO: Consider moving to global state */
>>>>>>> + /* Virtual control interface mapping */
>>>>>>> + void __iomem            *vctrl_base;
>>>>>>> +
>>>>>>> + /* base addresses in guest physical address space: */
>>>>>>> + gpa_t                   vgic_dist_base;         /* distributor */
>>>>>>> + union {
>>>>>>> +         /* either a GICv2 CPU interface */
>>>>>>> +         gpa_t                   vgic_cpu_base;
>>>>>>> +         /* or a number of GICv3 redistributor regions */
>>>>>>> +         gpa_t                   vgic_redist_base;
>>>>>>> + };
>>>>>>> +
>>>>>>> + /* distributor enabled */
>>>>>>> + u32                     enabled;
>>>>>>> +
>>>>>>> + struct vgic_irq         *spis;
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct vgic_v2_cpu_if {
>>>>>>> + u32             vgic_hcr;
>>>>>>> + u32             vgic_vmcr;
>>>>>>> + u32             vgic_misr;      /* Saved only */
>>>>>>> + u64             vgic_eisr;      /* Saved only */
>>>>>>> + u64             vgic_elrsr;     /* Saved only */
>>>>>>> + u32             vgic_apr;
>>>>>>> + u32             vgic_lr[VGIC_V2_MAX_LRS];
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct vgic_v3_cpu_if {
>>>>>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>>>>>>> + u32             vgic_hcr;
>>>>>>> + u32             vgic_vmcr;
>>>>>>> + u32             vgic_sre;       /* Restored only, change ignored */
>>>>>>> + u32             vgic_misr;      /* Saved only */
>>>>>>> + u32             vgic_eisr;      /* Saved only */
>>>>>>> + u32             vgic_elrsr;     /* Saved only */
>>>>>>> + u32             vgic_ap0r[4];
>>>>>>> + u32             vgic_ap1r[4];
>>>>>>> + u64             vgic_lr[VGIC_V3_MAX_LRS];
>>>>>>> +#endif
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct vgic_cpu {
>>>>>>> + /* CPU vif control registers for world switch */
>>>>>>> + union {
>>>>>>> +         struct vgic_v2_cpu_if   vgic_v2;
>>>>>>> +         struct vgic_v3_cpu_if   vgic_v3;
>>>>>>> + };
>>>>>>> +
>>>>>>> + /* TODO: Move nr_lr to a global state */
>>>>>>
>>>>>> what is our current plan and status about this TODO?
>>>>>
>>>>> The point is that the current HYP code is accessing this field. We do
>>>>> have this field in the current "global" struct vgic_params there as
>>>>> well, but this struct is (more or less) private to vgic-v2.c, so not
>>>>> easily accessible from virt/kvm/arm/hyp/*.c.
>>>>> So I suggest we keep this in here for the time being and eventually
>>>>> remove it (and rework the save/restore code) once we get rid of the old
>>>>> VGIC code.
>>>>>
>>>> Hmmm, I haven't tried it, but I don't understand why moving it now is
>>>> difficult.  I'd really like to avoid having a bunch of todo's lingering
>>>> around and having duplicated state in the new code.
>>>>
>>>> I think I noticed a number of places in this patch series which refers
>>>> tot he vgic_cpu->nr_lr instead of the global place already...
>>>>
>>> So I wrote a patch for this and it doesn't really look that bad.  I'll
>>> send it as part of a little prerequisite series later.
>>
>> I just fixed it as well - the private new VGIC part is trivial indeed.
>> But how did you solve the reference to the vgic_cpu.nr_lr in
>> virt/kvm/arm/hyp/vgic-v2-sr.c? With #ifdef .. #else? Or passing in the
>> number as in vgic-v3-sr.c?
>>
> 
> I sent you a couple of patches as I said I would.
> 
> I just used an extern with the kern_hyp_va() macro trickery applied.
> Not the prettiest thing in the world, but hey.  It should serve just
> fine for moving on with this, and then we can worry about the finesses
> as the vgic series progresses.

Agreed, thanks for those patches. I think I will just cherry-pick 2/3
and 3/3.
I am tempted to post my version of what you did in 1/3, which goes a bit
further and avoids some copying between different kind of structs.

Cheers,
Andre.

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

* Re: [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-04-06 14:53                 ` Andre Przywara
@ 2016-04-06 14:57                   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-06 14:57 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Wed, Apr 6, 2016 at 4:53 PM, Andre Przywara <andre.przywara@arm.com> wrote:
> Hej Christoffer,
>
> On 06/04/16 15:46, Christoffer Dall wrote:
>> On Wed, Apr 06, 2016 at 03:09:50PM +0100, Andre Przywara wrote:
>>>
>>>
>>> On 06/04/16 14:57, Christoffer Dall wrote:
>>>> On Tue, Apr 05, 2016 at 10:10:09PM +0200, Christoffer Dall wrote:
>>>>> On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On 29/03/16 14:09, Christoffer Dall wrote:
>>>>>>> On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
>>>>>>>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>>>>>>>
>>>>>>>> Add a new header file for the new and improved GIC implementation.
>>>>>>>> The big change is that we now have a struct vgic_irq per IRQ instead
>>>>>>>> of spreading all the information over various bitmaps.
>>>>>>>>
>>>>>>>> We include this new header conditionally from within the old header
>>>>>>>> file for the time being to avoid touching all the users.
>>>>>>>>
>>>>>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>>>>> ---
>>>>>>>>  include/kvm/arm_vgic.h  |   5 ++
>>>>>>>>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>  2 files changed, 203 insertions(+)
>>>>>>>>  create mode 100644 include/kvm/vgic/vgic.h
>>>>>>>>
>>>>>>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>>>>>>> index 7656a46..db289a2 100644
>>>>>>>> --- a/include/kvm/arm_vgic.h
>>>>>>>> +++ b/include/kvm/arm_vgic.h
>>>>>>>> @@ -19,6 +19,10 @@
>>>>>>>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>>>>>>>  #define __ASM_ARM_KVM_VGIC_H
>>>>>>>>
>>>>>>>> +#ifdef CONFIG_KVM_NEW_VGIC
>>>>>>>> +#include <kvm/vgic/vgic.h>
>>>>>>>> +#else
>>>>>>>> +
>>>>>>>>  #include <linux/kernel.h>
>>>>>>>>  #include <linux/kvm.h>
>>>>>>>>  #include <linux/irqreturn.h>
>>>>>>>> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>>>>>>>  }
>>>>>>>>  #endif
>>>>>>>>
>>>>>>>> +#endif   /* old VGIC include */
>>>>>>>>  #endif
>>>>>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000..659f8b1
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/include/kvm/vgic/vgic.h
>>>>>>>> @@ -0,0 +1,198 @@
>>>>>>>> +/*
>>>>>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>>>>>> + *
>>>>>>>> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
>>>>>>>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>>>>>>>> +
>>>>>>>> +#include <linux/kernel.h>
>>>>>>>> +#include <linux/kvm.h>
>>>>>>>> +#include <linux/irqreturn.h>
>>>>>>>> +#include <linux/spinlock.h>
>>>>>>>> +#include <linux/types.h>
>>>>>>>> +#include <kvm/iodev.h>
>>>>>>>> +
>>>>>>>> +#define VGIC_V3_MAX_CPUS 255
>>>>>>>> +#define VGIC_V2_MAX_CPUS 8
>>>>>>>> +#define VGIC_NR_IRQS_LEGACY     256
>>>>>>>> +#define VGIC_NR_SGIS             16
>>>>>>>> +#define VGIC_NR_PPIS             16
>>>>>>>> +#define VGIC_NR_PRIVATE_IRQS     (VGIC_NR_SGIS + VGIC_NR_PPIS)
>>>>>>>> +#define VGIC_MAX_PRIVATE (VGIC_NR_PRIVATE_IRQS - 1)
>>>>>>>> +#define VGIC_MAX_SPI             1019
>>>>>>>> +#define VGIC_MAX_RESERVED        1023
>>>>>>>> +#define VGIC_MIN_LPI             8192
>>>>>>>> +
>>>>>>>> +enum vgic_type {
>>>>>>>> + VGIC_V2,                /* Good ol' GICv2 */
>>>>>>>> + VGIC_V3,                /* New fancy GICv3 */
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/* same for all guests, as depending only on the _host's_ GIC model */
>>>>>>>> +struct vgic_global {
>>>>>>>> + /* type of the host GIC */
>>>>>>>> + enum vgic_type          type;
>>>>>>>> +
>>>>>>>> + /* Physical address of vgic virtual cpu interface */
>>>>>>>> + phys_addr_t             vcpu_base;
>>>>>>>> +
>>>>>>>> + /* virtual control interface mapping */
>>>>>>>> + void __iomem            *vctrl_base;
>>>>>>>> +
>>>>>>>> + /* Number of implemented list registers */
>>>>>>>> + int                     nr_lr;
>>>>>>>> +
>>>>>>>> + /* Maintenance IRQ number */
>>>>>>>> + unsigned int            maint_irq;
>>>>>>>> +
>>>>>>>> + /* maximum number of VCPUs allowed (GICv2 limits us to 8) */
>>>>>>>> + int                     max_gic_vcpus;
>>>>>>>> +
>>>>>>>> + /* Only needed for the legacy KVM_CREATE_IRQCHIP */
>>>>>>>> + bool                    can_emulate_gicv2;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +extern struct vgic_global kvm_vgic_global_state;
>>>>>>>> +
>>>>>>>> +#define VGIC_V2_MAX_LRS          (1 << 6)
>>>>>>>> +#define VGIC_V3_MAX_LRS          16
>>>>>>>> +#define VGIC_V3_LR_INDEX(lr)     (VGIC_V3_MAX_LRS - 1 - lr)
>>>>>>>> +
>>>>>>>> +enum vgic_irq_config {
>>>>>>>> + VGIC_CONFIG_EDGE = 0,
>>>>>>>> + VGIC_CONFIG_LEVEL
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct vgic_irq {
>>>>>>>> + spinlock_t irq_lock;            /* Protects the content of the struct */
>>>>>>>> + struct list_head ap_list;
>>>>>>>> +
>>>>>>>> + struct kvm_vcpu *vcpu;          /* SGIs and PPIs: The VCPU
>>>>>>>> +                                  * SPIs and LPIs: The VCPU whose ap_list
>>>>>>>> +                                  * on which this is queued.
>>>>>>>> +                                  */
>>>>>>>> +
>>>>>>>> + struct kvm_vcpu *target_vcpu;   /* The VCPU that this interrupt should
>>>>>>>> +                                  * be send to, as a result of the
>>>>>>>> +                                  * targets reg (v2) or the
>>>>>>>> +                                  * affinity reg (v3).
>>>>>>>> +                                  */
>>>>>>>> +
>>>>>>>> + u32 intid;                      /* Guest visible INTID */
>>>>>>>> + bool pending;
>>>>>>>> + bool line_level;                /* Level only */
>>>>>>>> + bool soft_pending;              /* Level only */
>>>>>>>> + bool active;                    /* not used for LPIs */
>>>>>>>> + bool enabled;
>>>>>>>> + bool hw;                        /* Tied to HW IRQ */
>>>>>>>> + u32 hwintid;                    /* HW INTID number */
>>>>>>>> + union {
>>>>>>>> +         u8 targets;                     /* GICv2 target VCPUs mask */
>>>>>>>> +         u32 mpidr;                      /* GICv3 target VCPU */
>>>>>>>> + };
>>>>>>>> + u8 source;                      /* GICv2 SGIs only */
>>>>>>>> + u8 priority;
>>>>>>>> + enum vgic_irq_config config;    /* Level or edge */
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct vgic_dist {
>>>>>>>> + bool                    in_kernel;
>>>>>>>> + bool                    ready;
>>>>>>>> +
>>>>>>>> + /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>>>>>>>> + u32                     vgic_model;
>>>>>>>> +
>>>>>>>> + int                     nr_spis;
>>>>>>>> +
>>>>>>>> + /* TODO: Consider moving to global state */
>>>>>>>> + /* Virtual control interface mapping */
>>>>>>>> + void __iomem            *vctrl_base;
>>>>>>>> +
>>>>>>>> + /* base addresses in guest physical address space: */
>>>>>>>> + gpa_t                   vgic_dist_base;         /* distributor */
>>>>>>>> + union {
>>>>>>>> +         /* either a GICv2 CPU interface */
>>>>>>>> +         gpa_t                   vgic_cpu_base;
>>>>>>>> +         /* or a number of GICv3 redistributor regions */
>>>>>>>> +         gpa_t                   vgic_redist_base;
>>>>>>>> + };
>>>>>>>> +
>>>>>>>> + /* distributor enabled */
>>>>>>>> + u32                     enabled;
>>>>>>>> +
>>>>>>>> + struct vgic_irq         *spis;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct vgic_v2_cpu_if {
>>>>>>>> + u32             vgic_hcr;
>>>>>>>> + u32             vgic_vmcr;
>>>>>>>> + u32             vgic_misr;      /* Saved only */
>>>>>>>> + u64             vgic_eisr;      /* Saved only */
>>>>>>>> + u64             vgic_elrsr;     /* Saved only */
>>>>>>>> + u32             vgic_apr;
>>>>>>>> + u32             vgic_lr[VGIC_V2_MAX_LRS];
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct vgic_v3_cpu_if {
>>>>>>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>>>>>>>> + u32             vgic_hcr;
>>>>>>>> + u32             vgic_vmcr;
>>>>>>>> + u32             vgic_sre;       /* Restored only, change ignored */
>>>>>>>> + u32             vgic_misr;      /* Saved only */
>>>>>>>> + u32             vgic_eisr;      /* Saved only */
>>>>>>>> + u32             vgic_elrsr;     /* Saved only */
>>>>>>>> + u32             vgic_ap0r[4];
>>>>>>>> + u32             vgic_ap1r[4];
>>>>>>>> + u64             vgic_lr[VGIC_V3_MAX_LRS];
>>>>>>>> +#endif
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct vgic_cpu {
>>>>>>>> + /* CPU vif control registers for world switch */
>>>>>>>> + union {
>>>>>>>> +         struct vgic_v2_cpu_if   vgic_v2;
>>>>>>>> +         struct vgic_v3_cpu_if   vgic_v3;
>>>>>>>> + };
>>>>>>>> +
>>>>>>>> + /* TODO: Move nr_lr to a global state */
>>>>>>>
>>>>>>> what is our current plan and status about this TODO?
>>>>>>
>>>>>> The point is that the current HYP code is accessing this field. We do
>>>>>> have this field in the current "global" struct vgic_params there as
>>>>>> well, but this struct is (more or less) private to vgic-v2.c, so not
>>>>>> easily accessible from virt/kvm/arm/hyp/*.c.
>>>>>> So I suggest we keep this in here for the time being and eventually
>>>>>> remove it (and rework the save/restore code) once we get rid of the old
>>>>>> VGIC code.
>>>>>>
>>>>> Hmmm, I haven't tried it, but I don't understand why moving it now is
>>>>> difficult.  I'd really like to avoid having a bunch of todo's lingering
>>>>> around and having duplicated state in the new code.
>>>>>
>>>>> I think I noticed a number of places in this patch series which refers
>>>>> tot he vgic_cpu->nr_lr instead of the global place already...
>>>>>
>>>> So I wrote a patch for this and it doesn't really look that bad.  I'll
>>>> send it as part of a little prerequisite series later.
>>>
>>> I just fixed it as well - the private new VGIC part is trivial indeed.
>>> But how did you solve the reference to the vgic_cpu.nr_lr in
>>> virt/kvm/arm/hyp/vgic-v2-sr.c? With #ifdef .. #else? Or passing in the
>>> number as in vgic-v3-sr.c?
>>>
>>
>> I sent you a couple of patches as I said I would.
>>
>> I just used an extern with the kern_hyp_va() macro trickery applied.
>> Not the prettiest thing in the world, but hey.  It should serve just
>> fine for moving on with this, and then we can worry about the finesses
>> as the vgic series progresses.
>
> Agreed, thanks for those patches. I think I will just cherry-pick 2/3
> and 3/3.
> I am tempted to post my version of what you did in 1/3, which goes a bit
> further and avoids some copying between different kind of structs.
>
ok, if you think you have a better solution, then that's fine.

-Christoffer

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

* [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-04-06 14:57                   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-06 14:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 6, 2016 at 4:53 PM, Andre Przywara <andre.przywara@arm.com> wrote:
> Hej Christoffer,
>
> On 06/04/16 15:46, Christoffer Dall wrote:
>> On Wed, Apr 06, 2016 at 03:09:50PM +0100, Andre Przywara wrote:
>>>
>>>
>>> On 06/04/16 14:57, Christoffer Dall wrote:
>>>> On Tue, Apr 05, 2016 at 10:10:09PM +0200, Christoffer Dall wrote:
>>>>> On Tue, Apr 05, 2016 at 02:34:42PM +0100, Andre Przywara wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On 29/03/16 14:09, Christoffer Dall wrote:
>>>>>>> On Fri, Mar 25, 2016 at 02:04:27AM +0000, Andre Przywara wrote:
>>>>>>>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>>>>>>>
>>>>>>>> Add a new header file for the new and improved GIC implementation.
>>>>>>>> The big change is that we now have a struct vgic_irq per IRQ instead
>>>>>>>> of spreading all the information over various bitmaps.
>>>>>>>>
>>>>>>>> We include this new header conditionally from within the old header
>>>>>>>> file for the time being to avoid touching all the users.
>>>>>>>>
>>>>>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>>>>> ---
>>>>>>>>  include/kvm/arm_vgic.h  |   5 ++
>>>>>>>>  include/kvm/vgic/vgic.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>  2 files changed, 203 insertions(+)
>>>>>>>>  create mode 100644 include/kvm/vgic/vgic.h
>>>>>>>>
>>>>>>>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>>>>>>>> index 7656a46..db289a2 100644
>>>>>>>> --- a/include/kvm/arm_vgic.h
>>>>>>>> +++ b/include/kvm/arm_vgic.h
>>>>>>>> @@ -19,6 +19,10 @@
>>>>>>>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>>>>>>>  #define __ASM_ARM_KVM_VGIC_H
>>>>>>>>
>>>>>>>> +#ifdef CONFIG_KVM_NEW_VGIC
>>>>>>>> +#include <kvm/vgic/vgic.h>
>>>>>>>> +#else
>>>>>>>> +
>>>>>>>>  #include <linux/kernel.h>
>>>>>>>>  #include <linux/kvm.h>
>>>>>>>>  #include <linux/irqreturn.h>
>>>>>>>> @@ -376,4 +380,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>>>>>>>  }
>>>>>>>>  #endif
>>>>>>>>
>>>>>>>> +#endif   /* old VGIC include */
>>>>>>>>  #endif
>>>>>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000..659f8b1
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/include/kvm/vgic/vgic.h
>>>>>>>> @@ -0,0 +1,198 @@
>>>>>>>> +/*
>>>>>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>>>>>> + *
>>>>>>>> + * 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 __ASM_ARM_KVM_VGIC_VGIC_H
>>>>>>>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>>>>>>>> +
>>>>>>>> +#include <linux/kernel.h>
>>>>>>>> +#include <linux/kvm.h>
>>>>>>>> +#include <linux/irqreturn.h>
>>>>>>>> +#include <linux/spinlock.h>
>>>>>>>> +#include <linux/types.h>
>>>>>>>> +#include <kvm/iodev.h>
>>>>>>>> +
>>>>>>>> +#define VGIC_V3_MAX_CPUS 255
>>>>>>>> +#define VGIC_V2_MAX_CPUS 8
>>>>>>>> +#define VGIC_NR_IRQS_LEGACY     256
>>>>>>>> +#define VGIC_NR_SGIS             16
>>>>>>>> +#define VGIC_NR_PPIS             16
>>>>>>>> +#define VGIC_NR_PRIVATE_IRQS     (VGIC_NR_SGIS + VGIC_NR_PPIS)
>>>>>>>> +#define VGIC_MAX_PRIVATE (VGIC_NR_PRIVATE_IRQS - 1)
>>>>>>>> +#define VGIC_MAX_SPI             1019
>>>>>>>> +#define VGIC_MAX_RESERVED        1023
>>>>>>>> +#define VGIC_MIN_LPI             8192
>>>>>>>> +
>>>>>>>> +enum vgic_type {
>>>>>>>> + VGIC_V2,                /* Good ol' GICv2 */
>>>>>>>> + VGIC_V3,                /* New fancy GICv3 */
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/* same for all guests, as depending only on the _host's_ GIC model */
>>>>>>>> +struct vgic_global {
>>>>>>>> + /* type of the host GIC */
>>>>>>>> + enum vgic_type          type;
>>>>>>>> +
>>>>>>>> + /* Physical address of vgic virtual cpu interface */
>>>>>>>> + phys_addr_t             vcpu_base;
>>>>>>>> +
>>>>>>>> + /* virtual control interface mapping */
>>>>>>>> + void __iomem            *vctrl_base;
>>>>>>>> +
>>>>>>>> + /* Number of implemented list registers */
>>>>>>>> + int                     nr_lr;
>>>>>>>> +
>>>>>>>> + /* Maintenance IRQ number */
>>>>>>>> + unsigned int            maint_irq;
>>>>>>>> +
>>>>>>>> + /* maximum number of VCPUs allowed (GICv2 limits us to 8) */
>>>>>>>> + int                     max_gic_vcpus;
>>>>>>>> +
>>>>>>>> + /* Only needed for the legacy KVM_CREATE_IRQCHIP */
>>>>>>>> + bool                    can_emulate_gicv2;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +extern struct vgic_global kvm_vgic_global_state;
>>>>>>>> +
>>>>>>>> +#define VGIC_V2_MAX_LRS          (1 << 6)
>>>>>>>> +#define VGIC_V3_MAX_LRS          16
>>>>>>>> +#define VGIC_V3_LR_INDEX(lr)     (VGIC_V3_MAX_LRS - 1 - lr)
>>>>>>>> +
>>>>>>>> +enum vgic_irq_config {
>>>>>>>> + VGIC_CONFIG_EDGE = 0,
>>>>>>>> + VGIC_CONFIG_LEVEL
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct vgic_irq {
>>>>>>>> + spinlock_t irq_lock;            /* Protects the content of the struct */
>>>>>>>> + struct list_head ap_list;
>>>>>>>> +
>>>>>>>> + struct kvm_vcpu *vcpu;          /* SGIs and PPIs: The VCPU
>>>>>>>> +                                  * SPIs and LPIs: The VCPU whose ap_list
>>>>>>>> +                                  * on which this is queued.
>>>>>>>> +                                  */
>>>>>>>> +
>>>>>>>> + struct kvm_vcpu *target_vcpu;   /* The VCPU that this interrupt should
>>>>>>>> +                                  * be send to, as a result of the
>>>>>>>> +                                  * targets reg (v2) or the
>>>>>>>> +                                  * affinity reg (v3).
>>>>>>>> +                                  */
>>>>>>>> +
>>>>>>>> + u32 intid;                      /* Guest visible INTID */
>>>>>>>> + bool pending;
>>>>>>>> + bool line_level;                /* Level only */
>>>>>>>> + bool soft_pending;              /* Level only */
>>>>>>>> + bool active;                    /* not used for LPIs */
>>>>>>>> + bool enabled;
>>>>>>>> + bool hw;                        /* Tied to HW IRQ */
>>>>>>>> + u32 hwintid;                    /* HW INTID number */
>>>>>>>> + union {
>>>>>>>> +         u8 targets;                     /* GICv2 target VCPUs mask */
>>>>>>>> +         u32 mpidr;                      /* GICv3 target VCPU */
>>>>>>>> + };
>>>>>>>> + u8 source;                      /* GICv2 SGIs only */
>>>>>>>> + u8 priority;
>>>>>>>> + enum vgic_irq_config config;    /* Level or edge */
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct vgic_dist {
>>>>>>>> + bool                    in_kernel;
>>>>>>>> + bool                    ready;
>>>>>>>> +
>>>>>>>> + /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>>>>>>>> + u32                     vgic_model;
>>>>>>>> +
>>>>>>>> + int                     nr_spis;
>>>>>>>> +
>>>>>>>> + /* TODO: Consider moving to global state */
>>>>>>>> + /* Virtual control interface mapping */
>>>>>>>> + void __iomem            *vctrl_base;
>>>>>>>> +
>>>>>>>> + /* base addresses in guest physical address space: */
>>>>>>>> + gpa_t                   vgic_dist_base;         /* distributor */
>>>>>>>> + union {
>>>>>>>> +         /* either a GICv2 CPU interface */
>>>>>>>> +         gpa_t                   vgic_cpu_base;
>>>>>>>> +         /* or a number of GICv3 redistributor regions */
>>>>>>>> +         gpa_t                   vgic_redist_base;
>>>>>>>> + };
>>>>>>>> +
>>>>>>>> + /* distributor enabled */
>>>>>>>> + u32                     enabled;
>>>>>>>> +
>>>>>>>> + struct vgic_irq         *spis;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct vgic_v2_cpu_if {
>>>>>>>> + u32             vgic_hcr;
>>>>>>>> + u32             vgic_vmcr;
>>>>>>>> + u32             vgic_misr;      /* Saved only */
>>>>>>>> + u64             vgic_eisr;      /* Saved only */
>>>>>>>> + u64             vgic_elrsr;     /* Saved only */
>>>>>>>> + u32             vgic_apr;
>>>>>>>> + u32             vgic_lr[VGIC_V2_MAX_LRS];
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct vgic_v3_cpu_if {
>>>>>>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>>>>>>>> + u32             vgic_hcr;
>>>>>>>> + u32             vgic_vmcr;
>>>>>>>> + u32             vgic_sre;       /* Restored only, change ignored */
>>>>>>>> + u32             vgic_misr;      /* Saved only */
>>>>>>>> + u32             vgic_eisr;      /* Saved only */
>>>>>>>> + u32             vgic_elrsr;     /* Saved only */
>>>>>>>> + u32             vgic_ap0r[4];
>>>>>>>> + u32             vgic_ap1r[4];
>>>>>>>> + u64             vgic_lr[VGIC_V3_MAX_LRS];
>>>>>>>> +#endif
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct vgic_cpu {
>>>>>>>> + /* CPU vif control registers for world switch */
>>>>>>>> + union {
>>>>>>>> +         struct vgic_v2_cpu_if   vgic_v2;
>>>>>>>> +         struct vgic_v3_cpu_if   vgic_v3;
>>>>>>>> + };
>>>>>>>> +
>>>>>>>> + /* TODO: Move nr_lr to a global state */
>>>>>>>
>>>>>>> what is our current plan and status about this TODO?
>>>>>>
>>>>>> The point is that the current HYP code is accessing this field. We do
>>>>>> have this field in the current "global" struct vgic_params there as
>>>>>> well, but this struct is (more or less) private to vgic-v2.c, so not
>>>>>> easily accessible from virt/kvm/arm/hyp/*.c.
>>>>>> So I suggest we keep this in here for the time being and eventually
>>>>>> remove it (and rework the save/restore code) once we get rid of the old
>>>>>> VGIC code.
>>>>>>
>>>>> Hmmm, I haven't tried it, but I don't understand why moving it now is
>>>>> difficult.  I'd really like to avoid having a bunch of todo's lingering
>>>>> around and having duplicated state in the new code.
>>>>>
>>>>> I think I noticed a number of places in this patch series which refers
>>>>> tot he vgic_cpu->nr_lr instead of the global place already...
>>>>>
>>>> So I wrote a patch for this and it doesn't really look that bad.  I'll
>>>> send it as part of a little prerequisite series later.
>>>
>>> I just fixed it as well - the private new VGIC part is trivial indeed.
>>> But how did you solve the reference to the vgic_cpu.nr_lr in
>>> virt/kvm/arm/hyp/vgic-v2-sr.c? With #ifdef .. #else? Or passing in the
>>> number as in vgic-v3-sr.c?
>>>
>>
>> I sent you a couple of patches as I said I would.
>>
>> I just used an extern with the kern_hyp_va() macro trickery applied.
>> Not the prettiest thing in the world, but hey.  It should serve just
>> fine for moving on with this, and then we can worry about the finesses
>> as the vgic series progresses.
>
> Agreed, thanks for those patches. I think I will just cherry-pick 2/3
> and 3/3.
> I am tempted to post my version of what you did in 1/3, which goes a bit
> further and avoids some copying between different kind of structs.
>
ok, if you think you have a better solution, then that's fine.

-Christoffer

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

* Re: [RFC PATCH 44/45] KVM: arm/arm64: vgic-new: Add dummy MSI implementation
  2016-03-31 18:16     ` Christoffer Dall
@ 2016-04-07 14:35       ` Eric Auger
  -1 siblings, 0 replies; 276+ messages in thread
From: Eric Auger @ 2016-04-07 14:35 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara
  Cc: Marc Zyngier, kvmarm, kvm, linux-arm-kernel

On 03/31/2016 08:16 PM, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:05:07AM +0000, Andre Przywara wrote:
>> Although we don't provide any virtual MSI functionality yet, we
>> need to implement the functions required by the KVM interface.
> 
> I don't feel like this commit text accurately describes what's happening
> in the code?
> 
> This seems to be about irqfds which work just fine on a GICv2m guest?

Yes those functions enable irqfd injection. gsi routing and msi routing
is not implemented yet.

Eric
> 
> Thanks,
> -Christoffer
> 
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic_irqfd.c | 51 ++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 51 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
>>
>> diff --git a/virt/kvm/arm/vgic/vgic_irqfd.c b/virt/kvm/arm/vgic/vgic_irqfd.c
>> new file mode 100644
>> index 0000000..3eee1bd
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_irqfd.c
>> @@ -0,0 +1,51 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * 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/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <trace/events/kvm.h>
>> +
>> +int kvm_irq_map_gsi(struct kvm *kvm,
>> +		    struct kvm_kernel_irq_routing_entry *entries,
>> +		    int gsi)
>> +{
>> +	return 0;
>> +}
>> +
>> +int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
>> +{
>> +	return pin;
>> +}
>> +
>> +int kvm_set_irq(struct kvm *kvm, int irq_source_id,
>> +		u32 irq, int level, bool line_status)
>> +{
>> +	unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
>> +
>> +	trace_kvm_set_irq(irq, level, irq_source_id);
>> +
>> +	BUG_ON(!vgic_initialized(kvm));
>> +
>> +	return kvm_vgic_inject_irq(kvm, 0, spi, level);
>> +}
>> +
>> +/* MSI not implemented yet */
>> +int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
>> +		struct kvm *kvm, int irq_source_id,
>> +		int level, bool line_status)
>> +{
>> +	return 0;
>> +}
>> -- 
>> 2.7.3
>>

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

* [RFC PATCH 44/45] KVM: arm/arm64: vgic-new: Add dummy MSI implementation
@ 2016-04-07 14:35       ` Eric Auger
  0 siblings, 0 replies; 276+ messages in thread
From: Eric Auger @ 2016-04-07 14:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/31/2016 08:16 PM, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:05:07AM +0000, Andre Przywara wrote:
>> Although we don't provide any virtual MSI functionality yet, we
>> need to implement the functions required by the KVM interface.
> 
> I don't feel like this commit text accurately describes what's happening
> in the code?
> 
> This seems to be about irqfds which work just fine on a GICv2m guest?

Yes those functions enable irqfd injection. gsi routing and msi routing
is not implemented yet.

Eric
> 
> Thanks,
> -Christoffer
> 
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic_irqfd.c | 51 ++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 51 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
>>
>> diff --git a/virt/kvm/arm/vgic/vgic_irqfd.c b/virt/kvm/arm/vgic/vgic_irqfd.c
>> new file mode 100644
>> index 0000000..3eee1bd
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_irqfd.c
>> @@ -0,0 +1,51 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * 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/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <trace/events/kvm.h>
>> +
>> +int kvm_irq_map_gsi(struct kvm *kvm,
>> +		    struct kvm_kernel_irq_routing_entry *entries,
>> +		    int gsi)
>> +{
>> +	return 0;
>> +}
>> +
>> +int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
>> +{
>> +	return pin;
>> +}
>> +
>> +int kvm_set_irq(struct kvm *kvm, int irq_source_id,
>> +		u32 irq, int level, bool line_status)
>> +{
>> +	unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
>> +
>> +	trace_kvm_set_irq(irq, level, irq_source_id);
>> +
>> +	BUG_ON(!vgic_initialized(kvm));
>> +
>> +	return kvm_vgic_inject_irq(kvm, 0, spi, level);
>> +}
>> +
>> +/* MSI not implemented yet */
>> +int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
>> +		struct kvm *kvm, int irq_source_id,
>> +		int level, bool line_status)
>> +{
>> +	return 0;
>> +}
>> -- 
>> 2.7.3
>>

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

* Re: [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-03-31  9:08     ` Christoffer Dall
@ 2016-04-11 10:53       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 10:53 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, kvm, kvmarm, linux-arm-kernel

Hi Christoffer,

On 31/03/16 10:08, Christoffer Dall wrote:
> Hi Andre,
> 
> [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
> 
> On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
>> We register each register group of the distributor and redistributors
>> as separate regions of the kvm-io-bus framework. This way calls get
>> directly handed over to the actual handler.
>> This puts a lot more regions into kvm-io-bus than what we use at the
>> moment on other architectures, so we will probably need to revisit the
>> implementation of the framework later to be more efficient.
> 
> Looking more carefully at the KVM IO bus stuff, it looks like it is
> indeed designed to be a *per device* thing you register, not a *per
> register* thing.
> 
> My comments to Vladimir's bug report notwithstanding, there's still a
> choice here to:
> 
> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> 
> 2) Build a KVM architectureal generic framework on top of the IO bus
> framework to handle individual register regions.
> 
> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> and handle the individual register region business locally within the
> arm/vgic code.
> 
> 
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> ---
>>  include/kvm/vgic/vgic.h       |   9 ++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
>>  3 files changed, 250 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 2ce9b4a..a8262c7 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -106,6 +106,12 @@ struct vgic_irq {
>>  	enum vgic_irq_config config;	/* Level or edge */
>>  };
>>  
>> +struct vgic_io_device {
>> +	gpa_t base_addr;
>> +	struct kvm_vcpu *redist_vcpu;
>> +	struct kvm_io_device dev;
>> +};
>> +
>>  struct vgic_dist {
>>  	bool			in_kernel;
>>  	bool			ready;
>> @@ -132,6 +138,9 @@ struct vgic_dist {
>>  	u32			enabled;
>>  
>>  	struct vgic_irq		*spis;
>> +
>> +	struct vgic_io_device	*dist_iodevs;
>> +	struct vgic_io_device	*redist_iodevs;
>>  };
>>  
>>  struct vgic_v2_cpu_if {
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> new file mode 100644
>> index 0000000..26c46e7
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -0,0 +1,194 @@
>> +/*
>> + * VGIC MMIO handling functions
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <kvm/iodev.h>
>> +#include <kvm/vgic/vgic.h>
>> +#include <linux/bitops.h>
>> +#include <linux/irqchip/arm-gic.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic_mmio.h"
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val)
>> +{
>> +	value = cpu_to_le32(value) >> (offset * 8);
>> +	memcpy(val, &value, len);
>> +}
>> +
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
>> +{
>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
>> +	return origvalue;
>> +}
>> +
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +void write_mask64(u64 value, int offset, int len, void *val)
>> +{
>> +	value = cpu_to_le64(value) >> (offset * 8);
>> +	memcpy(val, &value, len);
>> +}
>> +
>> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
> 
> I'm confuses in general.  Can you explain what these mask functions do
> overall at some higher level?

They do what you already guessed: take care about masking and endianness.

> I also keep having a feeling that mixing endianness stuff into the
> emulation code itself is the wrong way to go about it.

I agree.

>  The emulation
> code should just deal with register values of varying length and the
> interface to the VGIC should abstract all endianness nonsense for us,
> but I also think I've lost this argument some time in the past.  Sigh.
> 
> But, is the maximum read/write unit for any MMIO access not a 64-bit
> value?  So why can't we let the VGIC emulation code simply take/return a
> u64 which is then masked off/morphed into the right endianness outside
> the VGIC code?

The main problem is that the interface for kvm_io_bus is (int len, void
*val).
And since the guest's MMIO access can be of different length, we need to
take care of this in any case (since we need to know how many IRQs we
need to update). So we cannot get rid of the length parameter.
I guess what we could do is to either:
a) Declare the VGIC as purely little endian (which it really is, AFAIK).
We care about the necessary endianness conversion in mmio.c before
invoking the kvm_io_bus framework. But that means that we need to deal
with the _host's_ endianness in the VGIC emulation.
I think this is very close to what we currently do.    OR
b) Declare our VGIC emulation as always using the host's endianess. We
wouldn't need to care about endianness in the VGIC code anymore (is that
actually true?) We convert the MMIO traps (which are little endian
always) into the host's endianness before passing it on to kvm-io-bus.

I just see that this probably adds more to the confusion, oh well...

Thoughts?

Cheers,
Andre.

>> +u64 mask64(u64 origvalue, int offset, int len, const void *val)
>> +{
>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
>> +	return origvalue;
>> +}
>> +#endif
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, void *val)
>> +{
>> +	memset(val, 0, len);
>> +
>> +	return 0;
>> +}
>> +
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, const void *val)
>> +{
>> +	return 0;
>> +}
> 
> I dislike the use of 'this' as a parameter name, why not 'dev' ?
> 
>> +
>> +static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
>> +			      struct kvm_io_device *this,
>> +			      gpa_t addr, int len, void *val)
>> +{
>> +	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
>> +		vcpu->vcpu_id, (unsigned long long)addr);
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
>> +			       struct kvm_io_device *this,
>> +			       gpa_t addr, int len, const void *val)
>> +{
>> +	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
>> +		vcpu->vcpu_id, (unsigned long long)addr);
>> +	return 0;
>> +}
>> +
>> +struct vgic_register_region vgic_v2_dist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +};
>> +
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +				  struct vgic_register_region *reg_desc,
>> +				  struct vgic_io_device *region,
>> +				  int nr_irqs, bool offset_private)
>> +{
>> +	int bpi = reg_desc->bits_per_irq;
>> +	int offset = 0;
>> +	int len, ret;
>> +
>> +	region->base_addr	+= reg_desc->reg_offset;
>> +	region->redist_vcpu	= vcpu;
>> +
>> +	kvm_iodevice_init(&region->dev, &reg_desc->ops);
>> +
>> +	if (bpi) {
>> +		len = (bpi * nr_irqs) / 8;
>> +		if (offset_private)
>> +			offset = (bpi * VGIC_NR_PRIVATE_IRQS) / 8;
>> +	} else {
>> +		len = reg_desc->len;
>> +	}
>> +
>> +	mutex_lock(&kvm->slots_lock);
>> +	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +				      region->base_addr + offset,
>> +				      len - offset, &region->dev);
>> +	mutex_unlock(&kvm->slots_lock);
>> +
>> +	return ret;
>> +}
>> +
>> +int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>> +			       enum vgic_type type)
>> +{
>> +	struct vgic_io_device *regions;
>> +	struct vgic_register_region *reg_desc;
>> +	int nr_regions;
>> +	int nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +	int i;
>> +	int ret = 0;
>> +
>> +	switch (type) {
>> +	case VGIC_V2:
>> +		reg_desc = vgic_v2_dist_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>> +		break;
>> +	default:
>> +		BUG_ON(1);
>> +	}
>> +
>> +	regions = kmalloc_array(nr_regions, sizeof(struct vgic_io_device),
>> +				GFP_KERNEL);
>> +	if (!regions)
>> +		return -ENOMEM;
>> +
>> +	for (i = 0; i < nr_regions; i++) {
>> +		regions[i].base_addr	= dist_base_address;
>> +
>> +		ret = kvm_vgic_register_mmio_region(kvm, NULL, reg_desc,
>> +						    regions + i, nr_irqs,
>> +						    type == VGIC_V3);
>> +		if (ret)
>> +			break;
>> +
>> +		reg_desc++;
>> +	}
>> +
>> +	if (ret) {
>> +		mutex_lock(&kvm->slots_lock);
>> +		for (i--; i >= 0; i--)
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &regions[i].dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +	} else {
>> +		kvm->arch.vgic.dist_iodevs = regions;
>> +	}
>> +
>> +	return ret;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.h b/virt/kvm/arm/vgic/vgic_mmio.h
>> new file mode 100644
>> index 0000000..cf2314c
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.h
>> @@ -0,0 +1,47 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * 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_ARM_VGIC_MMIO_H__
>> +#define __KVM_ARM_VGIC_MMIO_H__
>> +
>> +struct vgic_register_region {
>> +	int reg_offset;
>> +	int len;
>> +	int bits_per_irq;
>> +	struct kvm_io_device_ops ops;
>> +};
>> +
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(name, read_ops, write_ops, bpi) \
>> +	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
>> +	 .ops.read = read_ops, .ops.write = write_ops}
>> +#define REGISTER_DESC_WITH_LENGTH(name, read_ops, write_ops, length) \
>> +	{.reg_offset = name, .bits_per_irq = 0, .len = length, \
>> +	 .ops.read = read_ops, .ops.write = write_ops}
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, void *val);
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, const void *val);
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +				  struct vgic_register_region *reg_desc,
>> +				  struct vgic_io_device *region,
>> +				  int nr_irqs, bool offset_private);
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val);
>> +void write_mask64(u64 value, int offset, int len, void *val);
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val);
>> +u64 mask64(u64 origvalue, int offset, int len, const void *val);
>> +
>> +#endif
>> -- 
>> 2.7.3
>>
>>
> 
> Thanks,
> -Christoffer
> 

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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-04-11 10:53       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 10:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 31/03/16 10:08, Christoffer Dall wrote:
> Hi Andre,
> 
> [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
> 
> On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
>> We register each register group of the distributor and redistributors
>> as separate regions of the kvm-io-bus framework. This way calls get
>> directly handed over to the actual handler.
>> This puts a lot more regions into kvm-io-bus than what we use at the
>> moment on other architectures, so we will probably need to revisit the
>> implementation of the framework later to be more efficient.
> 
> Looking more carefully at the KVM IO bus stuff, it looks like it is
> indeed designed to be a *per device* thing you register, not a *per
> register* thing.
> 
> My comments to Vladimir's bug report notwithstanding, there's still a
> choice here to:
> 
> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> 
> 2) Build a KVM architectureal generic framework on top of the IO bus
> framework to handle individual register regions.
> 
> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> and handle the individual register region business locally within the
> arm/vgic code.
> 
> 
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> ---
>>  include/kvm/vgic/vgic.h       |   9 ++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
>>  3 files changed, 250 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 2ce9b4a..a8262c7 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -106,6 +106,12 @@ struct vgic_irq {
>>  	enum vgic_irq_config config;	/* Level or edge */
>>  };
>>  
>> +struct vgic_io_device {
>> +	gpa_t base_addr;
>> +	struct kvm_vcpu *redist_vcpu;
>> +	struct kvm_io_device dev;
>> +};
>> +
>>  struct vgic_dist {
>>  	bool			in_kernel;
>>  	bool			ready;
>> @@ -132,6 +138,9 @@ struct vgic_dist {
>>  	u32			enabled;
>>  
>>  	struct vgic_irq		*spis;
>> +
>> +	struct vgic_io_device	*dist_iodevs;
>> +	struct vgic_io_device	*redist_iodevs;
>>  };
>>  
>>  struct vgic_v2_cpu_if {
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> new file mode 100644
>> index 0000000..26c46e7
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -0,0 +1,194 @@
>> +/*
>> + * VGIC MMIO handling functions
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <kvm/iodev.h>
>> +#include <kvm/vgic/vgic.h>
>> +#include <linux/bitops.h>
>> +#include <linux/irqchip/arm-gic.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic_mmio.h"
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val)
>> +{
>> +	value = cpu_to_le32(value) >> (offset * 8);
>> +	memcpy(val, &value, len);
>> +}
>> +
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
>> +{
>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
>> +	return origvalue;
>> +}
>> +
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +void write_mask64(u64 value, int offset, int len, void *val)
>> +{
>> +	value = cpu_to_le64(value) >> (offset * 8);
>> +	memcpy(val, &value, len);
>> +}
>> +
>> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
> 
> I'm confuses in general.  Can you explain what these mask functions do
> overall at some higher level?

They do what you already guessed: take care about masking and endianness.

> I also keep having a feeling that mixing endianness stuff into the
> emulation code itself is the wrong way to go about it.

I agree.

>  The emulation
> code should just deal with register values of varying length and the
> interface to the VGIC should abstract all endianness nonsense for us,
> but I also think I've lost this argument some time in the past.  Sigh.
> 
> But, is the maximum read/write unit for any MMIO access not a 64-bit
> value?  So why can't we let the VGIC emulation code simply take/return a
> u64 which is then masked off/morphed into the right endianness outside
> the VGIC code?

The main problem is that the interface for kvm_io_bus is (int len, void
*val).
And since the guest's MMIO access can be of different length, we need to
take care of this in any case (since we need to know how many IRQs we
need to update). So we cannot get rid of the length parameter.
I guess what we could do is to either:
a) Declare the VGIC as purely little endian (which it really is, AFAIK).
We care about the necessary endianness conversion in mmio.c before
invoking the kvm_io_bus framework. But that means that we need to deal
with the _host's_ endianness in the VGIC emulation.
I think this is very close to what we currently do.    OR
b) Declare our VGIC emulation as always using the host's endianess. We
wouldn't need to care about endianness in the VGIC code anymore (is that
actually true?) We convert the MMIO traps (which are little endian
always) into the host's endianness before passing it on to kvm-io-bus.

I just see that this probably adds more to the confusion, oh well...

Thoughts?

Cheers,
Andre.

>> +u64 mask64(u64 origvalue, int offset, int len, const void *val)
>> +{
>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
>> +	return origvalue;
>> +}
>> +#endif
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, void *val)
>> +{
>> +	memset(val, 0, len);
>> +
>> +	return 0;
>> +}
>> +
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, const void *val)
>> +{
>> +	return 0;
>> +}
> 
> I dislike the use of 'this' as a parameter name, why not 'dev' ?
> 
>> +
>> +static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
>> +			      struct kvm_io_device *this,
>> +			      gpa_t addr, int len, void *val)
>> +{
>> +	pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
>> +		vcpu->vcpu_id, (unsigned long long)addr);
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
>> +			       struct kvm_io_device *this,
>> +			       gpa_t addr, int len, const void *val)
>> +{
>> +	pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
>> +		vcpu->vcpu_id, (unsigned long long)addr);
>> +	return 0;
>> +}
>> +
>> +struct vgic_register_region vgic_v2_dist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
>> +		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>> +};
>> +
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +				  struct vgic_register_region *reg_desc,
>> +				  struct vgic_io_device *region,
>> +				  int nr_irqs, bool offset_private)
>> +{
>> +	int bpi = reg_desc->bits_per_irq;
>> +	int offset = 0;
>> +	int len, ret;
>> +
>> +	region->base_addr	+= reg_desc->reg_offset;
>> +	region->redist_vcpu	= vcpu;
>> +
>> +	kvm_iodevice_init(&region->dev, &reg_desc->ops);
>> +
>> +	if (bpi) {
>> +		len = (bpi * nr_irqs) / 8;
>> +		if (offset_private)
>> +			offset = (bpi * VGIC_NR_PRIVATE_IRQS) / 8;
>> +	} else {
>> +		len = reg_desc->len;
>> +	}
>> +
>> +	mutex_lock(&kvm->slots_lock);
>> +	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +				      region->base_addr + offset,
>> +				      len - offset, &region->dev);
>> +	mutex_unlock(&kvm->slots_lock);
>> +
>> +	return ret;
>> +}
>> +
>> +int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>> +			       enum vgic_type type)
>> +{
>> +	struct vgic_io_device *regions;
>> +	struct vgic_register_region *reg_desc;
>> +	int nr_regions;
>> +	int nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +	int i;
>> +	int ret = 0;
>> +
>> +	switch (type) {
>> +	case VGIC_V2:
>> +		reg_desc = vgic_v2_dist_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>> +		break;
>> +	default:
>> +		BUG_ON(1);
>> +	}
>> +
>> +	regions = kmalloc_array(nr_regions, sizeof(struct vgic_io_device),
>> +				GFP_KERNEL);
>> +	if (!regions)
>> +		return -ENOMEM;
>> +
>> +	for (i = 0; i < nr_regions; i++) {
>> +		regions[i].base_addr	= dist_base_address;
>> +
>> +		ret = kvm_vgic_register_mmio_region(kvm, NULL, reg_desc,
>> +						    regions + i, nr_irqs,
>> +						    type == VGIC_V3);
>> +		if (ret)
>> +			break;
>> +
>> +		reg_desc++;
>> +	}
>> +
>> +	if (ret) {
>> +		mutex_lock(&kvm->slots_lock);
>> +		for (i--; i >= 0; i--)
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &regions[i].dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +	} else {
>> +		kvm->arch.vgic.dist_iodevs = regions;
>> +	}
>> +
>> +	return ret;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.h b/virt/kvm/arm/vgic/vgic_mmio.h
>> new file mode 100644
>> index 0000000..cf2314c
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.h
>> @@ -0,0 +1,47 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * 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_ARM_VGIC_MMIO_H__
>> +#define __KVM_ARM_VGIC_MMIO_H__
>> +
>> +struct vgic_register_region {
>> +	int reg_offset;
>> +	int len;
>> +	int bits_per_irq;
>> +	struct kvm_io_device_ops ops;
>> +};
>> +
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(name, read_ops, write_ops, bpi) \
>> +	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
>> +	 .ops.read = read_ops, .ops.write = write_ops}
>> +#define REGISTER_DESC_WITH_LENGTH(name, read_ops, write_ops, length) \
>> +	{.reg_offset = name, .bits_per_irq = 0, .len = length, \
>> +	 .ops.read = read_ops, .ops.write = write_ops}
>> +
>> +int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, void *val);
>> +int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
>> +		       gpa_t addr, int len, const void *val);
>> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +				  struct vgic_register_region *reg_desc,
>> +				  struct vgic_io_device *region,
>> +				  int nr_irqs, bool offset_private);
>> +
>> +void write_mask32(u32 value, int offset, int len, void *val);
>> +void write_mask64(u64 value, int offset, int len, void *val);
>> +u32 mask32(u32 origvalue, int offset, int len, const void *val);
>> +u64 mask64(u64 origvalue, int offset, int len, const void *val);
>> +
>> +#endif
>> -- 
>> 2.7.3
>>
>>
> 
> Thanks,
> -Christoffer
> 

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

* Re: [RFC PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface
  2016-03-31  9:24     ` Christoffer Dall
@ 2016-04-11 11:09       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 11:09 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hej,

On 31/03/16 10:24, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:36AM +0000, Andre Przywara wrote:
>> Userland can access the emulated GIC to save and restore its state
>> for initialization or migration purposes.
>> The kvm_io_bus API requires an absolute gpa, which does not fit the
>> KVM_DEV_ARM_VGIC_GRP_DIST_REGS user API, that only provides relative
>> offsets. So we explicitly iterate our register list to connect
>> userland to the VGIC.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>> ---
>>  virt/kvm/arm/vgic/vgic.h      |  2 ++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 45 +++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 47 insertions(+)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 53730ba..a462e2b 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -25,6 +25,8 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>>  void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			int offset, int len, void *val);
>>  
>>  #ifdef CONFIG_KVM_ARM_VGIC_V3
>>  void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 26c46e7..e1fd17f 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -113,6 +113,51 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>>  };
>>  
>> +/*
>> + * Using kvm_io_bus_* to access GIC registers directly from userspace does
>> + * not work, since we would need the absolute IPA address of the register
>> + * in question, but the userland interface only provides relative offsets.
>> + * So we provide our own dispatcher function for that purpose here.
>> + */
>> +static int vgic_mmio_access(struct kvm_vcpu *vcpu,
>> +			    struct vgic_register_region *region, int nr_regions,
>> +			    bool is_write, int offset, int len, void *val)
>> +{
> 
> I suspect this is going to get rewored based on previous discussions
> with the IO api...
> 
>> +	int i;
>> +	struct vgic_io_device dev;
>> +
>> +	for (i = 0; i < nr_regions; i++) {
>> +		int reg_size = region[i].len;
>> +
>> +		if (!reg_size)
>> +			reg_size = (region[i].bits_per_irq * 1024) / 8;
>> +
>> +		if ((offset < region[i].reg_offset) ||
>> +		    (offset + len > region[i].reg_offset + reg_size))
>> +			continue;
>> +
>> +		dev.base_addr	= region[i].reg_offset;
>> +		dev.redist_vcpu	= vcpu;
>> +
>> +		if (is_write)
>> +			return region[i].ops.write(vcpu, &dev.dev,
>> +						   offset, len, val);
>> +		else
>> +			return region[i].ops.read(vcpu, &dev.dev,
>> +						  offset, len, val);
>> +	}
>> +
>> +	return -ENODEV;
>> +}
>> +
>> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			int offset, int len, void *val)
>> +{
>> +	return vgic_mmio_access(vcpu, vgic_v2_dist_registers,
>> +				ARRAY_SIZE(vgic_v2_dist_registers),
>> +				is_write, offset, len, val);
>> +}
>> +
> 
> this makes me wonder if the v2 region declarations and functions like
> this should go in a separate file?  vgic/mmio-v2.c ?

But we actually share a lot of functions like all the PENDING, ENABLED,
ACTIVE, PRIORITY, IGROUP register handlers. So we would need to export
them in order to be used by both the v2 and v3 emulation. This is what I
did for the existing v3 emulation, but I didn't like it very much.
Now we keep all of this private and static, both the handler functions
and the structures declaring the respective register layout.
I found this more appropriate now that v2 and v3 emulation are developed
hand in hand.
I see that the file gets pretty big, but it's still only roughly half
the size of the old vgic.c and also smaller than the combined old
vgic-v2-emul.c and vgic-v3-emul.c.

So I guess those 37K are just the price we need to pay for the beast
that the GIC actually is.

Cheers,
Andre.


> 
>>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  				  struct vgic_register_region *reg_desc,
>>  				  struct vgic_io_device *region,
>> -- 
>> 2.7.3
>>
> 

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

* [RFC PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface
@ 2016-04-11 11:09       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 11:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hej,

On 31/03/16 10:24, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:36AM +0000, Andre Przywara wrote:
>> Userland can access the emulated GIC to save and restore its state
>> for initialization or migration purposes.
>> The kvm_io_bus API requires an absolute gpa, which does not fit the
>> KVM_DEV_ARM_VGIC_GRP_DIST_REGS user API, that only provides relative
>> offsets. So we explicitly iterate our register list to connect
>> userland to the VGIC.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>> ---
>>  virt/kvm/arm/vgic/vgic.h      |  2 ++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 45 +++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 47 insertions(+)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 53730ba..a462e2b 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -25,6 +25,8 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>>  void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			int offset, int len, void *val);
>>  
>>  #ifdef CONFIG_KVM_ARM_VGIC_V3
>>  void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 26c46e7..e1fd17f 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -113,6 +113,51 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
>>  };
>>  
>> +/*
>> + * Using kvm_io_bus_* to access GIC registers directly from userspace does
>> + * not work, since we would need the absolute IPA address of the register
>> + * in question, but the userland interface only provides relative offsets.
>> + * So we provide our own dispatcher function for that purpose here.
>> + */
>> +static int vgic_mmio_access(struct kvm_vcpu *vcpu,
>> +			    struct vgic_register_region *region, int nr_regions,
>> +			    bool is_write, int offset, int len, void *val)
>> +{
> 
> I suspect this is going to get rewored based on previous discussions
> with the IO api...
> 
>> +	int i;
>> +	struct vgic_io_device dev;
>> +
>> +	for (i = 0; i < nr_regions; i++) {
>> +		int reg_size = region[i].len;
>> +
>> +		if (!reg_size)
>> +			reg_size = (region[i].bits_per_irq * 1024) / 8;
>> +
>> +		if ((offset < region[i].reg_offset) ||
>> +		    (offset + len > region[i].reg_offset + reg_size))
>> +			continue;
>> +
>> +		dev.base_addr	= region[i].reg_offset;
>> +		dev.redist_vcpu	= vcpu;
>> +
>> +		if (is_write)
>> +			return region[i].ops.write(vcpu, &dev.dev,
>> +						   offset, len, val);
>> +		else
>> +			return region[i].ops.read(vcpu, &dev.dev,
>> +						  offset, len, val);
>> +	}
>> +
>> +	return -ENODEV;
>> +}
>> +
>> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			int offset, int len, void *val)
>> +{
>> +	return vgic_mmio_access(vcpu, vgic_v2_dist_registers,
>> +				ARRAY_SIZE(vgic_v2_dist_registers),
>> +				is_write, offset, len, val);
>> +}
>> +
> 
> this makes me wonder if the v2 region declarations and functions like
> this should go in a separate file?  vgic/mmio-v2.c ?

But we actually share a lot of functions like all the PENDING, ENABLED,
ACTIVE, PRIORITY, IGROUP register handlers. So we would need to export
them in order to be used by both the v2 and v3 emulation. This is what I
did for the existing v3 emulation, but I didn't like it very much.
Now we keep all of this private and static, both the handler functions
and the structures declaring the respective register layout.
I found this more appropriate now that v2 and v3 emulation are developed
hand in hand.
I see that the file gets pretty big, but it's still only roughly half
the size of the old vgic.c and also smaller than the combined old
vgic-v2-emul.c and vgic-v3-emul.c.

So I guess those 37K are just the price we need to pay for the beast
that the GIC actually is.

Cheers,
Andre.


> 
>>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  				  struct vgic_register_region *reg_desc,
>>  				  struct vgic_io_device *region,
>> -- 
>> 2.7.3
>>
> 

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

* Re: [RFC PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-03-31  9:27     ` Christoffer Dall
@ 2016-04-11 11:23       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 11:23 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On 31/03/16 10:27, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:37AM +0000, Andre Przywara wrote:
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic.h      |  3 +++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 49 ++++++++++++++++++++++++++++++++++++++++++-
>>  2 files changed, 51 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index a462e2b..57aea8f 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -16,6 +16,9 @@
>>  #ifndef __KVM_ARM_VGIC_NEW_H__
>>  #define __KVM_ARM_VGIC_NEW_H__
>>  
>> +#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>> +#define IMPLEMENTER_ARM		0x43b
>> +
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid);
>>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index e1fd17f..e62366e 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -82,9 +82,56 @@ static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
>>  	return 0;
>>  }
>>  
>> +static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>> +				  struct kvm_io_device *this,
>> +				  gpa_t addr, int len, void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 value;
>> +
>> +	switch ((addr - iodev->base_addr) & ~3) {
>> +	case 0x0:
>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>> +		break;
>> +	case 0x4:
>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +		value = (value >> 5) - 1;
>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>> +		break;
>> +	case 0x8:
>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	write_mask32(value, addr & 3, len, val);
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>> +				   struct kvm_io_device *this,
>> +				   gpa_t addr, int len, const void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	/*
>> +	 * GICD_TYPER and GICD_IIDR are read-only, the upper three bytes of
>> +	 * GICD_CTLR are reserved.
>> +	 */
>> +	if (addr - iodev->base_addr >= 1)
>> +		return 0;
>> +
>> +	vcpu->kvm->arch.vgic.enabled = (*(u32 *)val) ? true : false;
>> +	/* TODO: is there anything to trigger at this point? */
> 
> I guess we should actually check if the vgic is enabled in PATH 11, and
> we should kick all VCPUs (or at least those with something pending) if
> we went from disabled to enabled?
> 
> We should probably also check this in the sync function...
> 
> Or do we enforce this enabled bool somewhere else that I missed?

Good point, I guess in the moment we just rely upon the VGIC being
enabled very early and never getting disabled.
So I will introduce checks in kvm_vgic_vcpu_pending_irq and the flush
function (which is called before entering the guest, I guess this is
what you meant with the "sync function"?), also kick all (?) VCPUs here
in case we enable the GIC.

Cheers,
Andre.

Note: just added comments about the direction of flushing/syncing since
I always forget which is which ;-)

>> +
>> +	return 0;
>> +}
>> +
>>  struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
>> +		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> -- 
>> 2.7.3
>>
> 

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

* [RFC PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-04-11 11:23       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

On 31/03/16 10:27, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:37AM +0000, Andre Przywara wrote:
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic.h      |  3 +++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 49 ++++++++++++++++++++++++++++++++++++++++++-
>>  2 files changed, 51 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index a462e2b..57aea8f 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -16,6 +16,9 @@
>>  #ifndef __KVM_ARM_VGIC_NEW_H__
>>  #define __KVM_ARM_VGIC_NEW_H__
>>  
>> +#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>> +#define IMPLEMENTER_ARM		0x43b
>> +
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid);
>>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index e1fd17f..e62366e 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -82,9 +82,56 @@ static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
>>  	return 0;
>>  }
>>  
>> +static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>> +				  struct kvm_io_device *this,
>> +				  gpa_t addr, int len, void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 value;
>> +
>> +	switch ((addr - iodev->base_addr) & ~3) {
>> +	case 0x0:
>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>> +		break;
>> +	case 0x4:
>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +		value = (value >> 5) - 1;
>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>> +		break;
>> +	case 0x8:
>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	write_mask32(value, addr & 3, len, val);
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>> +				   struct kvm_io_device *this,
>> +				   gpa_t addr, int len, const void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	/*
>> +	 * GICD_TYPER and GICD_IIDR are read-only, the upper three bytes of
>> +	 * GICD_CTLR are reserved.
>> +	 */
>> +	if (addr - iodev->base_addr >= 1)
>> +		return 0;
>> +
>> +	vcpu->kvm->arch.vgic.enabled = (*(u32 *)val) ? true : false;
>> +	/* TODO: is there anything to trigger at this point? */
> 
> I guess we should actually check if the vgic is enabled in PATH 11, and
> we should kick all VCPUs (or at least those with something pending) if
> we went from disabled to enabled?
> 
> We should probably also check this in the sync function...
> 
> Or do we enforce this enabled bool somewhere else that I missed?

Good point, I guess in the moment we just rely upon the VGIC being
enabled very early and never getting disabled.
So I will introduce checks in kvm_vgic_vcpu_pending_irq and the flush
function (which is called before entering the guest, I guess this is
what you meant with the "sync function"?), also kick all (?) VCPUs here
in case we enable the GIC.

Cheers,
Andre.

Note: just added comments about the direction of flushing/syncing since
I always forget which is which ;-)

>> +
>> +	return 0;
>> +}
>> +
>>  struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
>> +		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> -- 
>> 2.7.3
>>
> 

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

* Re: [RFC PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
  2016-03-31  9:35     ` Christoffer Dall
@ 2016-04-11 11:31       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 11:31 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On 31/03/16 10:35, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:39AM +0000, Andre Przywara wrote:
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic_mmio.c | 87 ++++++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 85 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 0688a69..8514f92 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -206,6 +206,89 @@ static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>>  	return 0;
>>  }
>>  
>> +static int vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
>> +				  struct kvm_io_device *this,
>> +				  gpa_t addr, int len, void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 intid = (addr - iodev->base_addr) * 8;
>> +	u32 value = 0;
>> +	int i;
>> +
>> +	if (iodev->redist_vcpu)
>> +		vcpu = iodev->redist_vcpu;
>> +
>> +	/* Loop over all IRQs affected by this read */
>> +	for (i = 0; i < len * 8; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +		if (irq->pending)
>> +			value |= (1U << i);
>> +		spin_unlock(&irq->irq_lock);
> 
> here there clearly is no need to take the lock (because a bool read is
> atomic), but that should be explained in a one-line comment.

Is that really true? Isn't it that another lock holder expects full
control over the IRQ struct, including the freedom to change values at
will without caring about other observers?
I might be too paranoid here, but I think I explicitly added the lock
here for a reason (which I don't remember anymore, sadly).

Cheers,
Andre.

>> +	}
>> +
>> +	write_mask32(value, addr & 3, len, val);
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
>> +				    struct kvm_io_device *this,
>> +				    gpa_t addr, int len, const void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 intid = (addr - iodev->base_addr) * 8;
>> +	int i;
>> +
>> +	if (iodev->redist_vcpu)
>> +		vcpu = iodev->redist_vcpu;
>> +
>> +	for_each_set_bit(i, val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +		irq->pending = true;
>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>> +			irq->soft_pending = true;
>> +
>> +		vgic_queue_irq(vcpu->kvm, irq);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>> +				    struct kvm_io_device *this,
>> +				    gpa_t addr, int len, const void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 intid = (addr - iodev->base_addr) * 8;
>> +	int i;
>> +
>> +	if (iodev->redist_vcpu)
>> +		vcpu = iodev->redist_vcpu;
>> +
>> +	for_each_set_bit(i, val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		if (irq->config == VGIC_CONFIG_LEVEL) {
>> +			irq->soft_pending = false;
>> +			irq->pending = irq->line_level;
>> +		} else {
>> +			irq->pending = false;
>> +		}
>> +		/* TODO: Does the exit/entry code take care of "unqueuing"? */
> 
> see previous patch comment
> 
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +	return 0;
>> +}
>> +
>>  struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>> @@ -216,9 +299,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>>  		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>> -- 
>> 2.7.3
>>
> 

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

* [RFC PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
@ 2016-04-11 11:31       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

On 31/03/16 10:35, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:39AM +0000, Andre Przywara wrote:
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic_mmio.c | 87 ++++++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 85 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 0688a69..8514f92 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -206,6 +206,89 @@ static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>>  	return 0;
>>  }
>>  
>> +static int vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
>> +				  struct kvm_io_device *this,
>> +				  gpa_t addr, int len, void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 intid = (addr - iodev->base_addr) * 8;
>> +	u32 value = 0;
>> +	int i;
>> +
>> +	if (iodev->redist_vcpu)
>> +		vcpu = iodev->redist_vcpu;
>> +
>> +	/* Loop over all IRQs affected by this read */
>> +	for (i = 0; i < len * 8; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +		if (irq->pending)
>> +			value |= (1U << i);
>> +		spin_unlock(&irq->irq_lock);
> 
> here there clearly is no need to take the lock (because a bool read is
> atomic), but that should be explained in a one-line comment.

Is that really true? Isn't it that another lock holder expects full
control over the IRQ struct, including the freedom to change values at
will without caring about other observers?
I might be too paranoid here, but I think I explicitly added the lock
here for a reason (which I don't remember anymore, sadly).

Cheers,
Andre.

>> +	}
>> +
>> +	write_mask32(value, addr & 3, len, val);
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
>> +				    struct kvm_io_device *this,
>> +				    gpa_t addr, int len, const void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 intid = (addr - iodev->base_addr) * 8;
>> +	int i;
>> +
>> +	if (iodev->redist_vcpu)
>> +		vcpu = iodev->redist_vcpu;
>> +
>> +	for_each_set_bit(i, val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +		irq->pending = true;
>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>> +			irq->soft_pending = true;
>> +
>> +		vgic_queue_irq(vcpu->kvm, irq);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>> +				    struct kvm_io_device *this,
>> +				    gpa_t addr, int len, const void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 intid = (addr - iodev->base_addr) * 8;
>> +	int i;
>> +
>> +	if (iodev->redist_vcpu)
>> +		vcpu = iodev->redist_vcpu;
>> +
>> +	for_each_set_bit(i, val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		if (irq->config == VGIC_CONFIG_LEVEL) {
>> +			irq->soft_pending = false;
>> +			irq->pending = irq->line_level;
>> +		} else {
>> +			irq->pending = false;
>> +		}
>> +		/* TODO: Does the exit/entry code take care of "unqueuing"? */
> 
> see previous patch comment
> 
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +	return 0;
>> +}
>> +
>>  struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>> @@ -216,9 +299,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>>  		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>> -- 
>> 2.7.3
>>
> 

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

* Re: [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
  2016-03-31  9:47     ` Christoffer Dall
@ 2016-04-11 11:40       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 11:40 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier; +Cc: linux-arm-kernel, kvmarm, kvm

On 31/03/16 10:47, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Implement the functionality for syncing IRQs between our emulation
>> and the list registers, which represent the guest's view of IRQs.
>> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
>> which gets called on guest entry and exit.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h     |   4 +
>>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h    |   4 +
>>  4 files changed, 373 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index f32b284..986f23f 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>>  
>> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>> +
>>  /**
>>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>>   *
>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>> index 0bf6f27..1cec423 100644
>> --- a/virt/kvm/arm/vgic/vgic-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>> @@ -14,11 +14,172 @@
>>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>   */
>>  
>> +#include <linux/irqchip/arm-gic.h>
>>  #include <linux/kvm.h>
>>  #include <linux/kvm_host.h>
>>  
>>  #include "vgic.h"
>>  
>> +/*
>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>> + *
>> + * Warning: Calling this function may modify *val.
>> + */
>> +static unsigned long *u64_to_bitmask(u64 *val)
>> +{
>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>> +	*val = (*val >> 32) | (*val << 32);
>> +#endif
>> +	return (unsigned long *)val;
>> +}
>> +
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>> +		u64 eisr = cpuif->vgic_eisr;
>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
>> +			struct vgic_irq *irq;
>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>> +
>> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>> +
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
>> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>> +		}
>> +	}
>> +
>> +	/* check and disable underflow maintenance IRQ */
>> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
>> +
>> +	/*
>> +	 * In the next iterations of the vcpu loop, if we sync the
>> +	 * vgic state after flushing it, but before entering the guest
>> +	 * (this happens for pending signals and vmid rollovers), then
>> +	 * make sure we don't pick up any old maintenance interrupts
>> +	 * here.
>> +	 */
>> +	cpuif->vgic_eisr = 0;
>> +}
>> +
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
>> +}
>> +
>> +/*
>> + * transfer the content of the LRs back into the corresponding ap_list:
>> + * - active bit is transferred as is
>> + * - pending bit is
>> + *   - transferred as is in case of edge sensitive IRQs
>> + *   - set to the line-level (resample time) for level sensitive IRQs
>> + */
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +	int lr;
>> +
>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>> +		u32 val = cpuif->vgic_lr[lr];
>> +		u32 intid = val & GICH_LR_VIRTUALID;
>> +		struct vgic_irq *irq;
>> +
>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/* Always preserve the active bit */
>> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
>> +
>> +		/* Edge is the only case where we preserve the pending bit */
>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>> +		    (val & GICH_LR_PENDING_BIT)) {
>> +			irq->pending = true;
>> +
>> +			if (intid < VGIC_NR_SGIS) {
>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>> +
>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
>> +				irq->source |= (1 << cpuid);
>> +			}
>> +		}
>> +
>> +		/* Clear soft pending state when level IRQs have been acked */
>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>> +		    !(val & GICH_LR_PENDING_BIT)) {
>> +			irq->soft_pending = false;
>> +			irq->pending = irq->line_level;
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +}
>> +
>> +/*
>> + * Populates the particular LR with the state of a given IRQ:
>> + * - for an edge sensitive IRQ the pending state is reset in the struct
>> + * - for a level sensitive IRQ the pending state value is unchanged;
>> + *   it will be resampled on deactivation
>> + *
>> + * If irq is not NULL, the irq_lock must be hold already by the caller.
>> + * If irq is NULL, the respective LR gets cleared.
>> + */
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>> +{
>> +	u32 val;
>> +
>> +	if (!irq) {
>> +		val = 0;
>> +		goto out;
>> +	}
>> +
>> +	val = irq->intid;
>> +
>> +	if (irq->pending) {
>> +		val |= GICH_LR_PENDING_BIT;
>> +
>> +		if (irq->config == VGIC_CONFIG_EDGE)
>> +			irq->pending = false;
>> +
>> +		if (irq->intid < VGIC_NR_SGIS) {
>> +			u32 src = ffs(irq->source);
>> +
>> +			BUG_ON(!src);
>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>> +			irq->source &= ~(1 << (src - 1));
>> +			if (irq->source)
>> +				irq->pending = true;
>> +		}
>> +	}
>> +
>> +	if (irq->active)
>> +		val |= GICH_LR_ACTIVE_BIT;
>> +
>> +	if (irq->hw) {
>> +		val |= GICH_LR_HW;
>> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
>> +	} else {
>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>> +			val |= GICH_LR_EOI;
>> +	}
> 
> shouldn't we start writing the priority here (and in the GICv3 version)?
> 
> (which has the fun consequence of having to compare priorities against
> the virtual priority filter in PATCH 11).

This is probably true.

I just feel I am getting overwhelmed with the change requests, can one
of you (Marc, Christoffer) fix this? Just use the existing code base, I
can rebase any change into the new tree.

The priority field in the v2 LR is only 5 bits long, is that covered by
the virtual priority filter you mentioned?

Cheers,
Andre.

> 
>> +
>> +out:
>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
>> +}
>> +
>>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>>  {
>>  	struct vgic_dist *dist = &kvm->arch.vgic;
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 29c753e..90a85bf 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>>  	return 0;
>>  }
>> +
>> +/**
>> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
>> + *
>> + * @vcpu: The VCPU pointer
>> + *
>> + * Go over the list of "interesting" interrupts, and prune those that we
>> + * won't have to consider in the near future.
>> + */
>> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq, *tmp;
>> +
>> +retry:
>> +	spin_lock(&vgic_cpu->ap_list_lock);
>> +
>> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
>> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		BUG_ON(vcpu != irq->vcpu);
>> +
>> +		target_vcpu = vgic_target_oracle(irq);
>> +
>> +		if (!target_vcpu) {
>> +			/*
>> +			 * We don't need to process this interrupt any
>> +			 * further, move it off the list.
>> +			 */
>> +			list_del_init(&irq->ap_list);
>> +			irq->vcpu = NULL;
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		if (target_vcpu == vcpu) {
>> +			/* We're on the right CPU */
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		/* This interrupt looks like it has to be migrated. */
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vgic_cpu->ap_list_lock);
>> +
>> +		/*
>> +		 * Ensure locking order by always locking the smallest
>> +		 * ID first.
>> +		 */
>> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
>> +			vcpuA = vcpu;
>> +			vcpuB = target_vcpu;
>> +		} else {
>> +			vcpuA = target_vcpu;
>> +			vcpuB = vcpu;
>> +		}
>> +
>> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/*
>> +		 * If the affinity has been preserved, move the
>> +		 * interrupt around. Otherwise, it means things have
>> +		 * changed while the interrupt was unlocked, and we
>> +		 * need to replay this.
>> +		 *
>> +		 * In all cases, we cannot trust the list not to have
>> +		 * changed, so we restart from the beginning.
>> +		 */
>> +		if (target_vcpu == vgic_target_oracle(irq)) {
>> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
>> +
>> +			list_del_init(&irq->ap_list);
>> +			irq->vcpu = target_vcpu;
>> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		goto retry;
>> +	}
>> +
>> +	spin_unlock(&vgic_cpu->ap_list_lock);
>> +}
>> +
>> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_process_maintenance(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_fold_lr_state(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +/*
>> + * Requires the ap_lock to be held.
>> + * If irq is not NULL, requires the IRQ lock to be held as well.
>> + * If irq is NULL, the list register gets cleared.
>> + */
>> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>> +				    struct vgic_irq *irq, int lr)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_populate_lr(vcpu, irq, lr);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_set_underflow(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq;
>> +	int count = 0;
>> +
>> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
>> +		spin_lock(&irq->irq_lock);
>> +		/* GICv2 SGIs can count for more than one... */
>> +		if (irq->intid < VGIC_NR_SGIS && irq->source)
>> +			count += hweight8(irq->source);
>> +		else
>> +			count++;
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +	return count;
>> +}
>> +
>> +/* requires the vcpu ap_lock to be held */
>> +static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +	struct vgic_irq *irq;
>> +	int count = 0;
>> +
>> +	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
>> +		vgic_set_underflow(vcpu);
>> +		vgic_sort_ap_list(vcpu);
>> +	}
>> +
>> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
>> +			goto next;
>> +
>> +		/*
>> +		 * If we get an SGI with multiple sources, try to get
>> +		 * them in all at once.
>> +		 */
>> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
>> +		    irq->intid < VGIC_NR_SGIS) {
>> +			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
>> +				vgic_populate_lr(vcpu, irq, count++);
>> +		} else {
>> +			vgic_populate_lr(vcpu, irq, count++);
>> +		}
>> +
>> +next:
>> +		spin_unlock(&irq->irq_lock);
>> +
>> +		if (count == vcpu->arch.vgic_cpu.nr_lr)
>> +			break;
>> +	}
>> +
>> +	vcpu->arch.vgic_cpu.used_lrs = count;
>> +
>> +	/* Nuke remaining LRs */
>> +	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
>> +		vgic_populate_lr(vcpu, NULL, count);
>> +}
>> +
>> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>> +{
>> +	vgic_process_maintenance_interrupt(vcpu);
>> +	vgic_fold_lr_state(vcpu);
>> +	vgic_prune_ap_list(vcpu);
>> +}
>> +
>> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>> +{
>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +	vgic_populate_lrs(vcpu);
>> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index b2faf00..95ef3cf 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -21,5 +21,9 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>>  
>>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>>  
>>  #endif
>> -- 
>> 2.7.3
>>
> 

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

* [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
@ 2016-04-11 11:40       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 11:40 UTC (permalink / raw)
  To: linux-arm-kernel

On 31/03/16 10:47, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Implement the functionality for syncing IRQs between our emulation
>> and the list registers, which represent the guest's view of IRQs.
>> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
>> which gets called on guest entry and exit.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h     |   4 +
>>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h    |   4 +
>>  4 files changed, 373 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index f32b284..986f23f 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>>  
>> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>> +
>>  /**
>>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>>   *
>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>> index 0bf6f27..1cec423 100644
>> --- a/virt/kvm/arm/vgic/vgic-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>> @@ -14,11 +14,172 @@
>>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>   */
>>  
>> +#include <linux/irqchip/arm-gic.h>
>>  #include <linux/kvm.h>
>>  #include <linux/kvm_host.h>
>>  
>>  #include "vgic.h"
>>  
>> +/*
>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>> + *
>> + * Warning: Calling this function may modify *val.
>> + */
>> +static unsigned long *u64_to_bitmask(u64 *val)
>> +{
>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>> +	*val = (*val >> 32) | (*val << 32);
>> +#endif
>> +	return (unsigned long *)val;
>> +}
>> +
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>> +		u64 eisr = cpuif->vgic_eisr;
>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
>> +			struct vgic_irq *irq;
>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>> +
>> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>> +
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
>> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>> +		}
>> +	}
>> +
>> +	/* check and disable underflow maintenance IRQ */
>> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
>> +
>> +	/*
>> +	 * In the next iterations of the vcpu loop, if we sync the
>> +	 * vgic state after flushing it, but before entering the guest
>> +	 * (this happens for pending signals and vmid rollovers), then
>> +	 * make sure we don't pick up any old maintenance interrupts
>> +	 * here.
>> +	 */
>> +	cpuif->vgic_eisr = 0;
>> +}
>> +
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
>> +}
>> +
>> +/*
>> + * transfer the content of the LRs back into the corresponding ap_list:
>> + * - active bit is transferred as is
>> + * - pending bit is
>> + *   - transferred as is in case of edge sensitive IRQs
>> + *   - set to the line-level (resample time) for level sensitive IRQs
>> + */
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +	int lr;
>> +
>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>> +		u32 val = cpuif->vgic_lr[lr];
>> +		u32 intid = val & GICH_LR_VIRTUALID;
>> +		struct vgic_irq *irq;
>> +
>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/* Always preserve the active bit */
>> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
>> +
>> +		/* Edge is the only case where we preserve the pending bit */
>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>> +		    (val & GICH_LR_PENDING_BIT)) {
>> +			irq->pending = true;
>> +
>> +			if (intid < VGIC_NR_SGIS) {
>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>> +
>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
>> +				irq->source |= (1 << cpuid);
>> +			}
>> +		}
>> +
>> +		/* Clear soft pending state when level IRQs have been acked */
>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>> +		    !(val & GICH_LR_PENDING_BIT)) {
>> +			irq->soft_pending = false;
>> +			irq->pending = irq->line_level;
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +}
>> +
>> +/*
>> + * Populates the particular LR with the state of a given IRQ:
>> + * - for an edge sensitive IRQ the pending state is reset in the struct
>> + * - for a level sensitive IRQ the pending state value is unchanged;
>> + *   it will be resampled on deactivation
>> + *
>> + * If irq is not NULL, the irq_lock must be hold already by the caller.
>> + * If irq is NULL, the respective LR gets cleared.
>> + */
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>> +{
>> +	u32 val;
>> +
>> +	if (!irq) {
>> +		val = 0;
>> +		goto out;
>> +	}
>> +
>> +	val = irq->intid;
>> +
>> +	if (irq->pending) {
>> +		val |= GICH_LR_PENDING_BIT;
>> +
>> +		if (irq->config == VGIC_CONFIG_EDGE)
>> +			irq->pending = false;
>> +
>> +		if (irq->intid < VGIC_NR_SGIS) {
>> +			u32 src = ffs(irq->source);
>> +
>> +			BUG_ON(!src);
>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>> +			irq->source &= ~(1 << (src - 1));
>> +			if (irq->source)
>> +				irq->pending = true;
>> +		}
>> +	}
>> +
>> +	if (irq->active)
>> +		val |= GICH_LR_ACTIVE_BIT;
>> +
>> +	if (irq->hw) {
>> +		val |= GICH_LR_HW;
>> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
>> +	} else {
>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>> +			val |= GICH_LR_EOI;
>> +	}
> 
> shouldn't we start writing the priority here (and in the GICv3 version)?
> 
> (which has the fun consequence of having to compare priorities against
> the virtual priority filter in PATCH 11).

This is probably true.

I just feel I am getting overwhelmed with the change requests, can one
of you (Marc, Christoffer) fix this? Just use the existing code base, I
can rebase any change into the new tree.

The priority field in the v2 LR is only 5 bits long, is that covered by
the virtual priority filter you mentioned?

Cheers,
Andre.

> 
>> +
>> +out:
>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
>> +}
>> +
>>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 new_targets)
>>  {
>>  	struct vgic_dist *dist = &kvm->arch.vgic;
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 29c753e..90a85bf 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -273,3 +273,207 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  	vgic_update_irq_pending(kvm, vcpu, intid, level);
>>  	return 0;
>>  }
>> +
>> +/**
>> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
>> + *
>> + * @vcpu: The VCPU pointer
>> + *
>> + * Go over the list of "interesting" interrupts, and prune those that we
>> + * won't have to consider in the near future.
>> + */
>> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq, *tmp;
>> +
>> +retry:
>> +	spin_lock(&vgic_cpu->ap_list_lock);
>> +
>> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
>> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		BUG_ON(vcpu != irq->vcpu);
>> +
>> +		target_vcpu = vgic_target_oracle(irq);
>> +
>> +		if (!target_vcpu) {
>> +			/*
>> +			 * We don't need to process this interrupt any
>> +			 * further, move it off the list.
>> +			 */
>> +			list_del_init(&irq->ap_list);
>> +			irq->vcpu = NULL;
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		if (target_vcpu == vcpu) {
>> +			/* We're on the right CPU */
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		/* This interrupt looks like it has to be migrated. */
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vgic_cpu->ap_list_lock);
>> +
>> +		/*
>> +		 * Ensure locking order by always locking the smallest
>> +		 * ID first.
>> +		 */
>> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
>> +			vcpuA = vcpu;
>> +			vcpuB = target_vcpu;
>> +		} else {
>> +			vcpuA = target_vcpu;
>> +			vcpuB = vcpu;
>> +		}
>> +
>> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/*
>> +		 * If the affinity has been preserved, move the
>> +		 * interrupt around. Otherwise, it means things have
>> +		 * changed while the interrupt was unlocked, and we
>> +		 * need to replay this.
>> +		 *
>> +		 * In all cases, we cannot trust the list not to have
>> +		 * changed, so we restart from the beginning.
>> +		 */
>> +		if (target_vcpu == vgic_target_oracle(irq)) {
>> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
>> +
>> +			list_del_init(&irq->ap_list);
>> +			irq->vcpu = target_vcpu;
>> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		goto retry;
>> +	}
>> +
>> +	spin_unlock(&vgic_cpu->ap_list_lock);
>> +}
>> +
>> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_process_maintenance(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_fold_lr_state(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +/*
>> + * Requires the ap_lock to be held.
>> + * If irq is not NULL, requires the IRQ lock to be held as well.
>> + * If irq is NULL, the list register gets cleared.
>> + */
>> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>> +				    struct vgic_irq *irq, int lr)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_populate_lr(vcpu, irq, lr);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_set_underflow(vcpu);
>> +	else
>> +		WARN(1, "GICv3 Not Implemented\n");
>> +}
>> +
>> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq;
>> +	int count = 0;
>> +
>> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
>> +		spin_lock(&irq->irq_lock);
>> +		/* GICv2 SGIs can count for more than one... */
>> +		if (irq->intid < VGIC_NR_SGIS && irq->source)
>> +			count += hweight8(irq->source);
>> +		else
>> +			count++;
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +	return count;
>> +}
>> +
>> +/* requires the vcpu ap_lock to be held */
>> +static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +	struct vgic_irq *irq;
>> +	int count = 0;
>> +
>> +	if (compute_ap_list_depth(vcpu) > vcpu->arch.vgic_cpu.nr_lr) {
>> +		vgic_set_underflow(vcpu);
>> +		vgic_sort_ap_list(vcpu);
>> +	}
>> +
>> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
>> +			goto next;
>> +
>> +		/*
>> +		 * If we get an SGI with multiple sources, try to get
>> +		 * them in all at once.
>> +		 */
>> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
>> +		    irq->intid < VGIC_NR_SGIS) {
>> +			while (irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
>> +				vgic_populate_lr(vcpu, irq, count++);
>> +		} else {
>> +			vgic_populate_lr(vcpu, irq, count++);
>> +		}
>> +
>> +next:
>> +		spin_unlock(&irq->irq_lock);
>> +
>> +		if (count == vcpu->arch.vgic_cpu.nr_lr)
>> +			break;
>> +	}
>> +
>> +	vcpu->arch.vgic_cpu.used_lrs = count;
>> +
>> +	/* Nuke remaining LRs */
>> +	for ( ; count < vcpu->arch.vgic_cpu.nr_lr; count++)
>> +		vgic_populate_lr(vcpu, NULL, count);
>> +}
>> +
>> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>> +{
>> +	vgic_process_maintenance_interrupt(vcpu);
>> +	vgic_fold_lr_state(vcpu);
>> +	vgic_prune_ap_list(vcpu);
>> +}
>> +
>> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>> +{
>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +	vgic_populate_lrs(vcpu);
>> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index b2faf00..95ef3cf 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -21,5 +21,9 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>>  
>>  void vgic_v2_irq_change_affinity(struct kvm *kvm, u32 intid, u8 target);
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>>  
>>  #endif
>> -- 
>> 2.7.3
>>
> 

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

* Re: [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  2016-03-31 11:31     ` Christoffer Dall
@ 2016-04-11 12:10       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 12:10 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On 31/03/16 12:31, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:43AM +0000, Andre Przywara wrote:
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 42 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 76657ce..cde153f 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>  	return 0;
>>  }
>>  
>> +static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
>> +				 struct kvm_io_device *this,
>> +				 gpa_t addr, int len, void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 intid = (addr - iodev->base_addr);
>> +	int i;
>> +
>> +	if (iodev->redist_vcpu)
>> +		vcpu = iodev->redist_vcpu;
>> +
>> +	for (i = 0; i < len; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		((u8 *)val)[i] = irq->targets;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
>> +				  struct kvm_io_device *this,
>> +				  gpa_t addr, int len, const void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 intid = (addr - iodev->base_addr);
>> +	int i;
>> +
>> +	/* GICD_ITARGETSR[0-7] are read-only */
>> +	if (intid < VGIC_NR_PRIVATE_IRQS)
>> +		return 0;
>> +
>> +	for (i = 0; i < len; i++)
>> +		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
>> +					    ((u8 *)val)[i]);
>> +
>> +	return 0;
>> +}
>> +
> 
> these functions are v2 specific but are in a generic file and are not
> named anything specific to v2?

Well, technically the target register is still defined for the GICv3
distributor, but just RES0 if affinity routing is enabled.
But I can of course easily add a _v2_ in here.

While I look at the function, it makes me wonder if the abstraction for
the affinity change call is actually correct at all. In contrast to the
other vgic_v<n>_* functions this one is about the _emulated_ VGIC model,
not the hardware GIC version.
Also we actually only have this one user here, the other call is about
initializing the affinity setting, for which this function is really
overkill.
So what about we move the content of the change_affinity function in
here (same for the v3 case later), and tackle the init case separately
(which is trivial)?

Cheers,
Andre.

> 
>>  struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>> @@ -491,7 +532,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +		vgic_mmio_read_target, vgic_mmio_write_target, 8),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>> -- 
>> 2.7.3
>>
>> --
>> 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] 276+ messages in thread

* [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
@ 2016-04-11 12:10       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 31/03/16 12:31, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:43AM +0000, Andre Przywara wrote:
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 42 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 76657ce..cde153f 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>  	return 0;
>>  }
>>  
>> +static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
>> +				 struct kvm_io_device *this,
>> +				 gpa_t addr, int len, void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 intid = (addr - iodev->base_addr);
>> +	int i;
>> +
>> +	if (iodev->redist_vcpu)
>> +		vcpu = iodev->redist_vcpu;
>> +
>> +	for (i = 0; i < len; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		((u8 *)val)[i] = irq->targets;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
>> +				  struct kvm_io_device *this,
>> +				  gpa_t addr, int len, const void *val)
>> +{
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 intid = (addr - iodev->base_addr);
>> +	int i;
>> +
>> +	/* GICD_ITARGETSR[0-7] are read-only */
>> +	if (intid < VGIC_NR_PRIVATE_IRQS)
>> +		return 0;
>> +
>> +	for (i = 0; i < len; i++)
>> +		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
>> +					    ((u8 *)val)[i]);
>> +
>> +	return 0;
>> +}
>> +
> 
> these functions are v2 specific but are in a generic file and are not
> named anything specific to v2?

Well, technically the target register is still defined for the GICv3
distributor, but just RES0 if affinity routing is enabled.
But I can of course easily add a _v2_ in here.

While I look at the function, it makes me wonder if the abstraction for
the affinity change call is actually correct at all. In contrast to the
other vgic_v<n>_* functions this one is about the _emulated_ VGIC model,
not the hardware GIC version.
Also we actually only have this one user here, the other call is about
initializing the affinity setting, for which this function is really
overkill.
So what about we move the content of the change_affinity function in
here (same for the v3 case later), and tackle the init case separately
(which is trivial)?

Cheers,
Andre.

> 
>>  struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>> @@ -491,7 +532,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>> +		vgic_mmio_read_target, vgic_mmio_write_target, 8),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>> -- 
>> 2.7.3
>>
>> --
>> 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] 276+ messages in thread

* Re: [RFC PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
  2016-03-31 11:48     ` Christoffer Dall
@ 2016-04-11 12:44       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 12:44 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 31/03/16 12:48, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:46AM +0000, Andre Przywara wrote:
>> Describe the GICv3 distributor and redistributor registers in our
>> structure. This adds a special macro to deal with the split of
>> SGI/PPI in the redistributor and SPIs in the distributor, which
>> allows us to reuse the existing GICv2 handlers for those registers
>> which are compatible.
>> Also we register the separate MMIO page for the redistributor
>> registers dealing with private interrupts.
>> GICv3 specific registers are only implemented as stubs at this time.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic.h      |  16 +++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 246 ++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 262 insertions(+)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 57aea8f..4b8952a 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -37,6 +37,10 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
>>  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
>> +int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			int offset, int len, void *val);
>> +int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			  int offset, int len, void *val);
>>  #else
>>  static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
>>  					       u64 mpidr)
>> @@ -59,6 +63,18 @@ static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
>>  static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>>  {
>>  }
>> +
>> +static inline int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +				      int offset, int len, void *val)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>> +static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +					int offset, int len, void *val)
>> +{
>> +	return -ENXIO;
>> +}
>>  #endif
>>  
>>  #endif
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 2ab8961..2d10c06 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -17,6 +17,8 @@
>>  #include <kvm/vgic/vgic.h>
>>  #include <linux/bitops.h>
>>  #include <linux/irqchip/arm-gic.h>
>> +#include <linux/irqchip/arm-gic-v3.h>
>> +#include <asm/kvm_emulate.h>
>>  
>>  #include "vgic.h"
>>  #include "vgic_mmio.h"
>> @@ -595,6 +597,105 @@ static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
>>  	return 0;
>>  }
>>  
>> +/*****************************/
>> +/* GICv3 emulation functions */
>> +/*****************************/
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +
>> +static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
>> +				  struct kvm_io_device *this,
>> +				  gpa_t addr, int len, void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
>> +				   struct kvm_io_device *this,
>> +				   gpa_t addr, int len, const void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_read_v3r_misc(struct kvm_vcpu *vcpu,
>> +				   struct kvm_io_device *this,
>> +				   gpa_t addr, int len, void *val)
>> +{
>> +	/* TODO: implement for ITS support */
>> +	return vgic_mmio_read_raz(vcpu, this, addr, len, val);
>> +}
>> +
>> +static int vgic_mmio_write_v3r_misc(struct kvm_vcpu *vcpu,
>> +				    struct kvm_io_device *this,
>> +				    gpa_t addr, int len, const void *val)
>> +{
>> +	/* TODO: implement for ITS support */
>> +	return vgic_mmio_write_wi(vcpu, this, addr, len, val);
>> +}
>> +
>> +static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
>> +				   struct kvm_io_device *this,
>> +				   gpa_t addr, int len, void *val)
>> +{
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
>> +				    struct kvm_io_device *this,
>> +				    gpa_t addr, int len, void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_read_v3r_propbase(struct kvm_vcpu *vcpu,
>> +				       struct kvm_io_device *this,
>> +				       gpa_t addr, int len, void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_v3r_propbase(struct kvm_vcpu *vcpu,
>> +				        struct kvm_io_device *this,
>> +				        gpa_t addr, int len, const void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_read_v3r_pendbase(struct kvm_vcpu *vcpu,
>> +				       struct kvm_io_device *this,
>> +				       gpa_t addr, int len, void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_v3r_pendbase(struct kvm_vcpu *vcpu,
>> +				        struct kvm_io_device *this,
>> +				        gpa_t addr, int len, const void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +#endif
>> +
>> +/*
>> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>> + * redistributors, while SPIs are covered by registers in the distributor
>> + * block. Trying to set private IRQs in this block gets ignored.
>> + * We take some special care here to fix the calculation of the register
>> + * offset.
>> + */
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(name, read_ops, write_ops, bpi) \
>> +	{.reg_offset = name, .bits_per_irq = 0, \
>> +	 .len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
>> +	 .ops.read = vgic_mmio_read_raz, .ops.write = vgic_mmio_write_wi, }, \
>> +	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
>> +	 .ops.read = read_ops, .ops.write = write_ops, }
> 
> why do we have two regions with the same offset and why does the one
> that actually implements a handler have length 0 ?

It's either .len or .bits_per_irq set, never both. If .len is 0, then
this register handles as many SPIs are there are configured, so we can
size the region accordingly. Registers with .len != 0 don't depend on
the number of IRQs (like CTLR or the like).
Deserves a comment, I guess.

For the two regions with the same offset: the actually registered offset
gets calculated upon registration, it starts after 32 IRQs for the v3
distributor.
The reg_offset value is used to calculate the IRQ number in the handler,
by keeping it aligned with IRQ 0 we always get the correct number
regardless if the actual region starting at IRQ 32 for the v3 dist or at
IRQ 0 for the v2 dist.

Admittedly a bit confusing, but allows us to use the very same handler
functions for both v2 and v3 without further code in each handler.

But actually this trick becomes moot now since I reworked the MMIO
dispatching anyway. Now we calculate the affected IRQ number by masking
the lower bits, so we don't depend on the .reg_offset anymore.
I will try to take a look if we can remove some of the weirdness of this
approach now.

>> +
>>  struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>> @@ -626,6 +727,73 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>>  		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>>  };
>>  
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +struct vgic_register_region vgic_v3_dist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>> +		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +};
>> +
>> +struct vgic_register_region vgic_v3_redist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>> +		vgic_mmio_read_v3r_misc, vgic_mmio_write_v3r_misc, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>> +		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>> +		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>> +		vgic_mmio_read_v3r_propbase, vgic_mmio_write_v3r_propbase, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>> +		vgic_mmio_read_v3r_pendbase, vgic_mmio_write_v3r_pendbase, 8),
>> +};
>> +
>> +struct vgic_register_region vgic_v3_private_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +};
>> +#endif
>> +
>>  /*
>>   * Using kvm_io_bus_* to access GIC registers directly from userspace does
>>   * not work, since we would need the absolute IPA address of the register
>> @@ -671,6 +839,24 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>>  				is_write, offset, len, val);
>>  }
>>  
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			int offset, int len, void *val)
>> +{
>> +	return vgic_mmio_access(vcpu, vgic_v3_dist_registers,
>> +				ARRAY_SIZE(vgic_v3_dist_registers),
>> +				is_write, offset, len, val);
>> +}
>> +
>> +int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			  int offset, int len, void *val)
>> +{
>> +	return vgic_mmio_access(vcpu, vgic_v3_redist_registers,
>> +				ARRAY_SIZE(vgic_v3_redist_registers),
>> +				is_write, offset, len, val);
>> +}
>> +#endif
>> +
>>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  				  struct vgic_register_region *reg_desc,
>>  				  struct vgic_io_device *region,
>> @@ -717,6 +903,12 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>>  		reg_desc = vgic_v2_dist_registers;
>>  		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>>  		break;
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +	case VGIC_V3:
>> +		reg_desc = vgic_v3_dist_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
>> +		break;
>> +#endif
>>  	default:
>>  		BUG_ON(1);
>>  	}
>> @@ -750,3 +942,57 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>>  
>>  	return ret;
>>  }
>> +
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
>> +{
>> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
>> +	int nr_regions = ARRAY_SIZE(vgic_v3_redist_registers) +
>> +			 ARRAY_SIZE(vgic_v3_private_registers);
>> +	struct kvm_vcpu *vcpu;
>> +	struct vgic_io_device *regions, *region;
>> +	int c, i, ret = 0;
>> +
>> +	regions = kmalloc(sizeof(struct vgic_io_device) * nr_regions * nr_vcpus,
>> +			  GFP_KERNEL);
>> +	if (!regions)
>> +		return -ENOMEM;
>> +
>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>> +		region = &regions[c * nr_regions];
>> +		for (i = 0; i < ARRAY_SIZE(vgic_v3_redist_registers); i++) {
>> +			region->base_addr = redist_base_address;
>> +			region->base_addr += c * 2 * SZ_64K;
>> +
>> +			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
>> +						vgic_v3_redist_registers + i,
>> +						region, VGIC_NR_PRIVATE_IRQS,
>> +						false);
>> +			if (ret)
>> +				break;
>> +			region++;
>> +		}
>> +		if (ret)
>> +			break;
>> +
>> +		for (i = 0; i < ARRAY_SIZE(vgic_v3_private_registers); i++) {
>> +			region->base_addr = redist_base_address;
>> +			region->base_addr += c * 2 * SZ_64K + SZ_64K;
>> +			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
>> +						vgic_v3_private_registers + i,
>> +						region, VGIC_NR_PRIVATE_IRQS,
>> +						false);
>> +			if (ret)
>> +				break;
>> +			region++;
>> +		}
>> +		if (ret)
>> +			break;
>> +	}
>> +
>> +	if (!ret)
>> +		kvm->arch.vgic.redist_iodevs = regions;
>> +
>> +	return ret;
> 
> I'm not going to review all this in detail until we've figured out the
> general approach to the IO bus stuff.

Good idea, since I changed quite a lot of this by now ;-)

Cheers,
Andre.

> 
>> +}
>> +#endif
>> -- 
>> 2.7.3
>>
>> --
>> 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] 276+ messages in thread

* [RFC PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 emulation framework
@ 2016-04-11 12:44       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 12:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 31/03/16 12:48, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:46AM +0000, Andre Przywara wrote:
>> Describe the GICv3 distributor and redistributor registers in our
>> structure. This adds a special macro to deal with the split of
>> SGI/PPI in the redistributor and SPIs in the distributor, which
>> allows us to reuse the existing GICv2 handlers for those registers
>> which are compatible.
>> Also we register the separate MMIO page for the redistributor
>> registers dealing with private interrupts.
>> GICv3 specific registers are only implemented as stubs at this time.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic.h      |  16 +++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 246 ++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 262 insertions(+)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 57aea8f..4b8952a 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -37,6 +37,10 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
>>  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
>> +int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			int offset, int len, void *val);
>> +int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			  int offset, int len, void *val);
>>  #else
>>  static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
>>  					       u64 mpidr)
>> @@ -59,6 +63,18 @@ static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
>>  static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>>  {
>>  }
>> +
>> +static inline int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +				      int offset, int len, void *val)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>> +static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +					int offset, int len, void *val)
>> +{
>> +	return -ENXIO;
>> +}
>>  #endif
>>  
>>  #endif
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 2ab8961..2d10c06 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -17,6 +17,8 @@
>>  #include <kvm/vgic/vgic.h>
>>  #include <linux/bitops.h>
>>  #include <linux/irqchip/arm-gic.h>
>> +#include <linux/irqchip/arm-gic-v3.h>
>> +#include <asm/kvm_emulate.h>
>>  
>>  #include "vgic.h"
>>  #include "vgic_mmio.h"
>> @@ -595,6 +597,105 @@ static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
>>  	return 0;
>>  }
>>  
>> +/*****************************/
>> +/* GICv3 emulation functions */
>> +/*****************************/
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +
>> +static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
>> +				  struct kvm_io_device *this,
>> +				  gpa_t addr, int len, void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
>> +				   struct kvm_io_device *this,
>> +				   gpa_t addr, int len, const void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_read_v3r_misc(struct kvm_vcpu *vcpu,
>> +				   struct kvm_io_device *this,
>> +				   gpa_t addr, int len, void *val)
>> +{
>> +	/* TODO: implement for ITS support */
>> +	return vgic_mmio_read_raz(vcpu, this, addr, len, val);
>> +}
>> +
>> +static int vgic_mmio_write_v3r_misc(struct kvm_vcpu *vcpu,
>> +				    struct kvm_io_device *this,
>> +				    gpa_t addr, int len, const void *val)
>> +{
>> +	/* TODO: implement for ITS support */
>> +	return vgic_mmio_write_wi(vcpu, this, addr, len, val);
>> +}
>> +
>> +static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
>> +				   struct kvm_io_device *this,
>> +				   gpa_t addr, int len, void *val)
>> +{
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
>> +				    struct kvm_io_device *this,
>> +				    gpa_t addr, int len, void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_read_v3r_propbase(struct kvm_vcpu *vcpu,
>> +				       struct kvm_io_device *this,
>> +				       gpa_t addr, int len, void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_v3r_propbase(struct kvm_vcpu *vcpu,
>> +				        struct kvm_io_device *this,
>> +				        gpa_t addr, int len, const void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_read_v3r_pendbase(struct kvm_vcpu *vcpu,
>> +				       struct kvm_io_device *this,
>> +				       gpa_t addr, int len, void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +
>> +static int vgic_mmio_write_v3r_pendbase(struct kvm_vcpu *vcpu,
>> +				        struct kvm_io_device *this,
>> +				        gpa_t addr, int len, const void *val)
>> +{
>> +	/* TODO: implement */
>> +	return 0;
>> +}
>> +#endif
>> +
>> +/*
>> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>> + * redistributors, while SPIs are covered by registers in the distributor
>> + * block. Trying to set private IRQs in this block gets ignored.
>> + * We take some special care here to fix the calculation of the register
>> + * offset.
>> + */
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(name, read_ops, write_ops, bpi) \
>> +	{.reg_offset = name, .bits_per_irq = 0, \
>> +	 .len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
>> +	 .ops.read = vgic_mmio_read_raz, .ops.write = vgic_mmio_write_wi, }, \
>> +	{.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
>> +	 .ops.read = read_ops, .ops.write = write_ops, }
> 
> why do we have two regions with the same offset and why does the one
> that actually implements a handler have length 0 ?

It's either .len or .bits_per_irq set, never both. If .len is 0, then
this register handles as many SPIs are there are configured, so we can
size the region accordingly. Registers with .len != 0 don't depend on
the number of IRQs (like CTLR or the like).
Deserves a comment, I guess.

For the two regions with the same offset: the actually registered offset
gets calculated upon registration, it starts after 32 IRQs for the v3
distributor.
The reg_offset value is used to calculate the IRQ number in the handler,
by keeping it aligned with IRQ 0 we always get the correct number
regardless if the actual region starting at IRQ 32 for the v3 dist or at
IRQ 0 for the v2 dist.

Admittedly a bit confusing, but allows us to use the very same handler
functions for both v2 and v3 without further code in each handler.

But actually this trick becomes moot now since I reworked the MMIO
dispatching anyway. Now we calculate the affected IRQ number by masking
the lower bits, so we don't depend on the .reg_offset anymore.
I will try to take a look if we can remove some of the weirdness of this
approach now.

>> +
>>  struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>> @@ -626,6 +727,73 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>>  		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>>  };
>>  
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +struct vgic_register_region vgic_v3_dist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>> +		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +};
>> +
>> +struct vgic_register_region vgic_v3_redist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>> +		vgic_mmio_read_v3r_misc, vgic_mmio_write_v3r_misc, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>> +		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>> +		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>> +		vgic_mmio_read_v3r_propbase, vgic_mmio_write_v3r_propbase, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>> +		vgic_mmio_read_v3r_pendbase, vgic_mmio_write_v3r_pendbase, 8),
>> +};
>> +
>> +struct vgic_register_region vgic_v3_private_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +};
>> +#endif
>> +
>>  /*
>>   * Using kvm_io_bus_* to access GIC registers directly from userspace does
>>   * not work, since we would need the absolute IPA address of the register
>> @@ -671,6 +839,24 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>>  				is_write, offset, len, val);
>>  }
>>  
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			int offset, int len, void *val)
>> +{
>> +	return vgic_mmio_access(vcpu, vgic_v3_dist_registers,
>> +				ARRAY_SIZE(vgic_v3_dist_registers),
>> +				is_write, offset, len, val);
>> +}
>> +
>> +int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
>> +			  int offset, int len, void *val)
>> +{
>> +	return vgic_mmio_access(vcpu, vgic_v3_redist_registers,
>> +				ARRAY_SIZE(vgic_v3_redist_registers),
>> +				is_write, offset, len, val);
>> +}
>> +#endif
>> +
>>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  				  struct vgic_register_region *reg_desc,
>>  				  struct vgic_io_device *region,
>> @@ -717,6 +903,12 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>>  		reg_desc = vgic_v2_dist_registers;
>>  		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>>  		break;
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +	case VGIC_V3:
>> +		reg_desc = vgic_v3_dist_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
>> +		break;
>> +#endif
>>  	default:
>>  		BUG_ON(1);
>>  	}
>> @@ -750,3 +942,57 @@ int vgic_register_dist_regions(struct kvm *kvm, gpa_t dist_base_address,
>>  
>>  	return ret;
>>  }
>> +
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
>> +{
>> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
>> +	int nr_regions = ARRAY_SIZE(vgic_v3_redist_registers) +
>> +			 ARRAY_SIZE(vgic_v3_private_registers);
>> +	struct kvm_vcpu *vcpu;
>> +	struct vgic_io_device *regions, *region;
>> +	int c, i, ret = 0;
>> +
>> +	regions = kmalloc(sizeof(struct vgic_io_device) * nr_regions * nr_vcpus,
>> +			  GFP_KERNEL);
>> +	if (!regions)
>> +		return -ENOMEM;
>> +
>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>> +		region = &regions[c * nr_regions];
>> +		for (i = 0; i < ARRAY_SIZE(vgic_v3_redist_registers); i++) {
>> +			region->base_addr = redist_base_address;
>> +			region->base_addr += c * 2 * SZ_64K;
>> +
>> +			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
>> +						vgic_v3_redist_registers + i,
>> +						region, VGIC_NR_PRIVATE_IRQS,
>> +						false);
>> +			if (ret)
>> +				break;
>> +			region++;
>> +		}
>> +		if (ret)
>> +			break;
>> +
>> +		for (i = 0; i < ARRAY_SIZE(vgic_v3_private_registers); i++) {
>> +			region->base_addr = redist_base_address;
>> +			region->base_addr += c * 2 * SZ_64K + SZ_64K;
>> +			ret = kvm_vgic_register_mmio_region(kvm, vcpu,
>> +						vgic_v3_private_registers + i,
>> +						region, VGIC_NR_PRIVATE_IRQS,
>> +						false);
>> +			if (ret)
>> +				break;
>> +			region++;
>> +		}
>> +		if (ret)
>> +			break;
>> +	}
>> +
>> +	if (!ret)
>> +		kvm->arch.vgic.redist_iodevs = regions;
>> +
>> +	return ret;
> 
> I'm not going to review all this in detail until we've figured out the
> general approach to the IO bus stuff.

Good idea, since I changed quite a lot of this by now ;-)

Cheers,
Andre.

> 
>> +}
>> +#endif
>> -- 
>> 2.7.3
>>
>> --
>> 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] 276+ messages in thread

* Re: [RFC PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
  2016-03-31 11:53     ` Christoffer Dall
@ 2016-04-11 13:00       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 13:00 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 31/03/16 12:53, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:47AM +0000, Andre Przywara wrote:
>> As in the GICv2 emulation we handle those three registers in one
>> function.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic.h      |  2 ++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 38 ++++++++++++++++++++++++++++++++++++--
>>  2 files changed, 38 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 4b8952a..0db1abe 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -19,6 +19,8 @@
>>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>>  #define IMPLEMENTER_ARM		0x43b
>>  
>> +#define INTERRUPT_ID_BITS_SPIS	10
>> +
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid);
>>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 2d10c06..13e101f 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -606,7 +606,29 @@ static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
>>  				  struct kvm_io_device *this,
>>  				  gpa_t addr, int len, void *val)
>>  {
>> -	/* TODO: implement */
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 value = 0;
>> +
>> +	switch ((addr - iodev->base_addr) & ~3) {
>> +	case GICD_CTLR:
>> +		if (vcpu->kvm->arch.vgic.enabled)
>> +		       value |=	GICD_CTLR_ENABLE_SS_G1;
>> +		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
>> +		break;
>> +	case GICD_TYPER:
>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +		value = (value >> 5) - 1;
>> +		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
>> +		break;
>> +	case GICD_IIDR:
>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	write_mask32(value, addr & 3, len, val);
>>  	return 0;
>>  }
>>  
>> @@ -614,7 +636,19 @@ static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
>>  				   struct kvm_io_device *this,
>>  				   gpa_t addr, int len, const void *val)
>>  {
>> -	/* TODO: implement */
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	bool enabled;
>> +
>> +	/* These are not the bits you are looking for ... */
> 
> haha, nice.  But I don't understand what this case is?

Of the 16 bytes this region covers (CTLR, TYPER, IIDR) only the first
byte is writeable, the rest is WI.
I am afraid I have to replace the cool quote with something more
meaningful ...

>> +	if (addr - iodev->base_addr > 0)
>> +		return 0;
>> +
>> +	/* We only care about the enable bit, all other bits are WI. */
>> +	enabled = *(u8*)val & GICD_CTLR_ENABLE_SS_G1;
>> +
>> +	vcpu->kvm->arch.vgic.enabled = enabled;
> 
> I think some of the comments from the v2 side apply here as well.

Agreed.

Cheers,
Andre.

>> +
>>  	return 0;
>>  }
>>  
>> -- 
>> 2.7.3
>>
> 

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

* [RFC PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
@ 2016-04-11 13:00       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 31/03/16 12:53, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:47AM +0000, Andre Przywara wrote:
>> As in the GICv2 emulation we handle those three registers in one
>> function.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic.h      |  2 ++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 38 ++++++++++++++++++++++++++++++++++++--
>>  2 files changed, 38 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 4b8952a..0db1abe 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -19,6 +19,8 @@
>>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>>  #define IMPLEMENTER_ARM		0x43b
>>  
>> +#define INTERRUPT_ID_BITS_SPIS	10
>> +
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid);
>>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 2d10c06..13e101f 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -606,7 +606,29 @@ static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
>>  				  struct kvm_io_device *this,
>>  				  gpa_t addr, int len, void *val)
>>  {
>> -	/* TODO: implement */
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	u32 value = 0;
>> +
>> +	switch ((addr - iodev->base_addr) & ~3) {
>> +	case GICD_CTLR:
>> +		if (vcpu->kvm->arch.vgic.enabled)
>> +		       value |=	GICD_CTLR_ENABLE_SS_G1;
>> +		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
>> +		break;
>> +	case GICD_TYPER:
>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +		value = (value >> 5) - 1;
>> +		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
>> +		break;
>> +	case GICD_IIDR:
>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	write_mask32(value, addr & 3, len, val);
>>  	return 0;
>>  }
>>  
>> @@ -614,7 +636,19 @@ static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
>>  				   struct kvm_io_device *this,
>>  				   gpa_t addr, int len, const void *val)
>>  {
>> -	/* TODO: implement */
>> +	struct vgic_io_device *iodev = container_of(this,
>> +						    struct vgic_io_device, dev);
>> +	bool enabled;
>> +
>> +	/* These are not the bits you are looking for ... */
> 
> haha, nice.  But I don't understand what this case is?

Of the 16 bytes this region covers (CTLR, TYPER, IIDR) only the first
byte is writeable, the rest is WI.
I am afraid I have to replace the cool quote with something more
meaningful ...

>> +	if (addr - iodev->base_addr > 0)
>> +		return 0;
>> +
>> +	/* We only care about the enable bit, all other bits are WI. */
>> +	enabled = *(u8*)val & GICD_CTLR_ENABLE_SS_G1;
>> +
>> +	vcpu->kvm->arch.vgic.enabled = enabled;
> 
> I think some of the comments from the v2 side apply here as well.

Agreed.

Cheers,
Andre.

>> +
>>  	return 0;
>>  }
>>  
>> -- 
>> 2.7.3
>>
> 

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

* Re: [RFC PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
  2016-03-31 12:07     ` Christoffer Dall
@ 2016-04-11 13:11       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 13:11 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 31/03/16 13:07, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:51AM +0000, Andre Przywara wrote:
>> In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
>> by a MMIO write, but with a system register write. KVM knows about
>> that register already, we just need to implement the handler and wire
>> it up to the core KVM/ARM code.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h       |   8 ++++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 101 ++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 109 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index a8262c7..ab5fcc7 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -202,6 +202,14 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>>  void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>>  void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>>  
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
>> +#else
>> +static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
>> +{
>> +}
>> +#endif
>> +
>>  /**
>>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>>   *
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 44fdba5..7eb6b93 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -1139,4 +1139,105 @@ int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
>>  
>>  	return ret;
>>  }
>> +
>> +/*
>> + * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
>> + * generation register ICC_SGI1R_EL1) with a given VCPU.
>> + * If the VCPU's MPIDR matches, return the level0 affinity, otherwise
>> + * return -1.
>> + */
>> +static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct kvm_vcpu *vcpu)
>> +{
>> +	unsigned long affinity;
>> +	int level0;
>> +
>> +	/*
>> +	 * Split the current VCPU's MPIDR into affinity level 0 and the
>> +	 * rest as this is what we have to compare against.
>> +	 */
>> +	affinity = kvm_vcpu_get_mpidr_aff(vcpu);
>> +	level0 = MPIDR_AFFINITY_LEVEL(affinity, 0);
>> +	affinity &= ~MPIDR_LEVEL_MASK;
>> +
>> +	/* bail out if the upper three levels don't match */
>> +	if (sgi_aff != affinity)
>> +		return -1;
>> +
>> +	/* Is this VCPU's bit set in the mask ? */
>> +	if (!(sgi_cpu_mask & BIT(level0)))
>> +		return -1;
>> +
>> +	return level0;
>> +}
>> +
>> +#define SGI_AFFINITY_LEVEL(reg, level) \
>> +	((((reg) & ICC_SGI1R_AFFINITY_## level ##_MASK) \
>> +	>> ICC_SGI1R_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
> 
> wholy crap?  What is this?  Yikes, this is already in the kernel.  Oh
> well, I'm not going to try to understand it again then.

This is to isolate a certain SGI affinity encoding, which uses a
different bitmasking than the MPIDR. Plus we use the existing defines
here, which looks a bit more complicated than it actually is: basically
just masking and shifting.
I added a comment.

Cheers,
Andre.

>> +
>> +/**
>> + * vgic_v3_dispatch_sgi - handle SGI requests from VCPUs
>> + * @vcpu: The VCPU requesting a SGI
>> + * @reg: The value written into the ICC_SGI1R_EL1 register by that VCPU
>> + *
>> + * With GICv3 (and ARE=1) CPUs trigger SGIs by writing to a system register.
>> + * This will trap in sys_regs.c and call this function.
>> + * This ICC_SGI1R_EL1 register contains the upper three affinity levels of the
>> + * target processors as well as a bitmask of 16 Aff0 CPUs.
>> + * If the interrupt routing mode bit is not set, we iterate over all VCPUs to
>> + * check for matching ones. If this bit is set, we signal all, but not the
>> + * calling VCPU.
>> + */
>> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
>> +{
>> +	struct kvm *kvm = vcpu->kvm;
>> +	struct kvm_vcpu *c_vcpu;
>> +	u16 target_cpus;
>> +	u64 mpidr;
>> +	int sgi, c;
>> +	int vcpu_id = vcpu->vcpu_id;
>> +	bool broadcast;
>> +
>> +	sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
>> +	broadcast = reg & BIT(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
>> +	target_cpus = (reg & ICC_SGI1R_TARGET_LIST_MASK) >> ICC_SGI1R_TARGET_LIST_SHIFT;
>> +	mpidr = SGI_AFFINITY_LEVEL(reg, 3);
>> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 2);
>> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 1);
>> +
>> +	/*
>> +	 * We iterate over all VCPUs to find the MPIDRs matching the request.
>> +	 * If we have handled one CPU, we clear it's bit to detect early
> 
> s/it's/its/
> 
>> +	 * if we are already finished. This avoids iterating through all
>> +	 * VCPUs when most of the times we just signal a single VCPU.
>> +	 */
>> +	kvm_for_each_vcpu(c, c_vcpu, kvm) {
>> +		struct vgic_irq *irq;
>> +
>> +		/* Exit early if we have dealt with all requested CPUs */
>> +		if (!broadcast && target_cpus == 0)
>> +			break;
>> +
>> +		/* Don't signal the calling VCPU */
>> +		if (broadcast && c == vcpu_id)
>> +			continue;
>> +
>> +		if (!broadcast) {
>> +			int level0;
>> +
>> +			level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
>> +			if (level0 == -1)
>> +				continue;
>> +
>> +			/* remove this matching VCPU from the mask */
>> +			target_cpus &= ~BIT(level0);
>> +		}
>> +
>> +		irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +		irq->pending = true;
>> +
>> +		vgic_queue_irq(vcpu->kvm, irq);
>> +	}
> 
> eventually I suspect we should implement a linear time 'give me a vcpu
> based on this mpidr' lookup function, but this should be fine for now.
> 
>> +}
>>  #endif
>> -- 
>> 2.7.3
>>
>> --
>> 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] 276+ messages in thread

* [RFC PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
@ 2016-04-11 13:11       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 13:11 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 31/03/16 13:07, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:51AM +0000, Andre Przywara wrote:
>> In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
>> by a MMIO write, but with a system register write. KVM knows about
>> that register already, we just need to implement the handler and wire
>> it up to the core KVM/ARM code.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/vgic/vgic.h       |   8 ++++
>>  virt/kvm/arm/vgic/vgic_mmio.c | 101 ++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 109 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index a8262c7..ab5fcc7 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -202,6 +202,14 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>>  void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>>  void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>>  
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
>> +#else
>> +static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
>> +{
>> +}
>> +#endif
>> +
>>  /**
>>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>>   *
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 44fdba5..7eb6b93 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -1139,4 +1139,105 @@ int vgic_register_redist_regions(struct kvm *kvm, gpa_t redist_base_address)
>>  
>>  	return ret;
>>  }
>> +
>> +/*
>> + * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
>> + * generation register ICC_SGI1R_EL1) with a given VCPU.
>> + * If the VCPU's MPIDR matches, return the level0 affinity, otherwise
>> + * return -1.
>> + */
>> +static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct kvm_vcpu *vcpu)
>> +{
>> +	unsigned long affinity;
>> +	int level0;
>> +
>> +	/*
>> +	 * Split the current VCPU's MPIDR into affinity level 0 and the
>> +	 * rest as this is what we have to compare against.
>> +	 */
>> +	affinity = kvm_vcpu_get_mpidr_aff(vcpu);
>> +	level0 = MPIDR_AFFINITY_LEVEL(affinity, 0);
>> +	affinity &= ~MPIDR_LEVEL_MASK;
>> +
>> +	/* bail out if the upper three levels don't match */
>> +	if (sgi_aff != affinity)
>> +		return -1;
>> +
>> +	/* Is this VCPU's bit set in the mask ? */
>> +	if (!(sgi_cpu_mask & BIT(level0)))
>> +		return -1;
>> +
>> +	return level0;
>> +}
>> +
>> +#define SGI_AFFINITY_LEVEL(reg, level) \
>> +	((((reg) & ICC_SGI1R_AFFINITY_## level ##_MASK) \
>> +	>> ICC_SGI1R_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
> 
> wholy crap?  What is this?  Yikes, this is already in the kernel.  Oh
> well, I'm not going to try to understand it again then.

This is to isolate a certain SGI affinity encoding, which uses a
different bitmasking than the MPIDR. Plus we use the existing defines
here, which looks a bit more complicated than it actually is: basically
just masking and shifting.
I added a comment.

Cheers,
Andre.

>> +
>> +/**
>> + * vgic_v3_dispatch_sgi - handle SGI requests from VCPUs
>> + * @vcpu: The VCPU requesting a SGI
>> + * @reg: The value written into the ICC_SGI1R_EL1 register by that VCPU
>> + *
>> + * With GICv3 (and ARE=1) CPUs trigger SGIs by writing to a system register.
>> + * This will trap in sys_regs.c and call this function.
>> + * This ICC_SGI1R_EL1 register contains the upper three affinity levels of the
>> + * target processors as well as a bitmask of 16 Aff0 CPUs.
>> + * If the interrupt routing mode bit is not set, we iterate over all VCPUs to
>> + * check for matching ones. If this bit is set, we signal all, but not the
>> + * calling VCPU.
>> + */
>> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
>> +{
>> +	struct kvm *kvm = vcpu->kvm;
>> +	struct kvm_vcpu *c_vcpu;
>> +	u16 target_cpus;
>> +	u64 mpidr;
>> +	int sgi, c;
>> +	int vcpu_id = vcpu->vcpu_id;
>> +	bool broadcast;
>> +
>> +	sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
>> +	broadcast = reg & BIT(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
>> +	target_cpus = (reg & ICC_SGI1R_TARGET_LIST_MASK) >> ICC_SGI1R_TARGET_LIST_SHIFT;
>> +	mpidr = SGI_AFFINITY_LEVEL(reg, 3);
>> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 2);
>> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 1);
>> +
>> +	/*
>> +	 * We iterate over all VCPUs to find the MPIDRs matching the request.
>> +	 * If we have handled one CPU, we clear it's bit to detect early
> 
> s/it's/its/
> 
>> +	 * if we are already finished. This avoids iterating through all
>> +	 * VCPUs when most of the times we just signal a single VCPU.
>> +	 */
>> +	kvm_for_each_vcpu(c, c_vcpu, kvm) {
>> +		struct vgic_irq *irq;
>> +
>> +		/* Exit early if we have dealt with all requested CPUs */
>> +		if (!broadcast && target_cpus == 0)
>> +			break;
>> +
>> +		/* Don't signal the calling VCPU */
>> +		if (broadcast && c == vcpu_id)
>> +			continue;
>> +
>> +		if (!broadcast) {
>> +			int level0;
>> +
>> +			level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
>> +			if (level0 == -1)
>> +				continue;
>> +
>> +			/* remove this matching VCPU from the mask */
>> +			target_cpus &= ~BIT(level0);
>> +		}
>> +
>> +		irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +		irq->pending = true;
>> +
>> +		vgic_queue_irq(vcpu->kvm, irq);
>> +	}
> 
> eventually I suspect we should implement a linear time 'give me a vcpu
> based on this mpidr' lookup function, but this should be fine for now.
> 
>> +}
>>  #endif
>> -- 
>> 2.7.3
>>
>> --
>> 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] 276+ messages in thread

* Re: [RFC PATCH 45/45] KVM: arm/arm64: vgic-new: enable build
  2016-03-31 18:18     ` Christoffer Dall
@ 2016-04-11 14:45       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 14:45 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 31/03/16 19:18, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:05:08AM +0000, Andre Przywara wrote:
>> Now that the new VGIC implementation has reached feature parity with
>> the old one, add the new files to the build system and add a Kconfig
>> option to switch between the two versions.
>> We set the default to the new version to get maximum test coverage,
>> in case people experience problems they can switch back to the old
>> behaviour if needed.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  arch/arm/kvm/Kconfig    |  7 +++++++
>>  arch/arm/kvm/Makefile   | 10 ++++++++++
>>  arch/arm64/kvm/Kconfig  |  7 +++++++
>>  arch/arm64/kvm/Makefile | 10 ++++++++++
>>  4 files changed, 34 insertions(+)
>>
>> diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
>> index 95a0005..02abfff 100644
>> --- a/arch/arm/kvm/Kconfig
>> +++ b/arch/arm/kvm/Kconfig
>> @@ -46,6 +46,13 @@ config KVM_ARM_HOST
>>  	---help---
>>  	  Provides host support for ARM processors.
>>  
>> +config KVM_NEW_VGIC
>> +	bool "New VGIC implementation"
>> +	depends on KVM
>> +	default y
>> +	---help---
>> +	  uses the new VGIC implementation
>> +
> 
> I had imagined we'd name it in the reverse, so the option would have
> been CONFIG_KVM_VGIC_LEGACY, but I guess the net effect should be the
> same, assuming most people just go with the default anyway.

I think originally the assumption was to make the old VGIC the default
in the beginning, but that changed later. By that time I considered it
too tedious to change all patches in this regard, so I just kept the old
symbol and semantic in.
Shouldn't matter, really, I guess there are arguments for both ways.

Cheers,
Andre.

>>  source drivers/vhost/Kconfig
>>  
>>  endif # VIRTUALIZATION
>> diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
>> index eb1bf43..aa7d724 100644
>> --- a/arch/arm/kvm/Makefile
>> +++ b/arch/arm/kvm/Makefile
>> @@ -21,7 +21,17 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp/
>>  obj-y += kvm-arm.o init.o interrupts.o
>>  obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
>>  obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
>> +
>> +ifeq ($(CONFIG_KVM_NEW_VGIC),y)
>> +obj-y += $(KVM)/arm/vgic/vgic.o
>> +obj-y += $(KVM)/arm/vgic/vgic_init.o
>> +obj-y += $(KVM)/arm/vgic/vgic_irqfd.o
>> +obj-y += $(KVM)/arm/vgic/vgic-v2.o
>> +obj-y += $(KVM)/arm/vgic/vgic_mmio.o
>> +obj-y += $(KVM)/arm/vgic/vgic_kvm_device.o
>> +else
>>  obj-y += $(KVM)/arm/vgic.o
>>  obj-y += $(KVM)/arm/vgic-v2.o
>>  obj-y += $(KVM)/arm/vgic-v2-emul.o
>> +endif
>>  obj-y += $(KVM)/arm/arch_timer.o
>> diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
>> index de7450d..3f0e1ce 100644
>> --- a/arch/arm64/kvm/Kconfig
>> +++ b/arch/arm64/kvm/Kconfig
>> @@ -55,6 +55,13 @@ config KVM_ARM_PMU
>>  	  Adds support for a virtual Performance Monitoring Unit (PMU) in
>>  	  virtual machines.
>>  
>> +config KVM_NEW_VGIC
>> +	bool "New VGIC implementation"
>> +	depends on KVM
>> +	default y
>> +        ---help---
>> +          uses the new VGIC implementation
>> +
>>  source drivers/vhost/Kconfig
>>  
>>  endif # VIRTUALIZATION
>> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
>> index 122cff4..2f5d431 100644
>> --- a/arch/arm64/kvm/Makefile
>> +++ b/arch/arm64/kvm/Makefile
>> @@ -20,10 +20,20 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
>>  
>> +ifeq ($(CONFIG_KVM_NEW_VGIC),y)
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_init.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_irqfd.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_mmio.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_kvm_device.o
>> +else
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
>> +endif
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
>>  kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
>> -- 
>> 2.7.3
>>
>> --
>> 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] 276+ messages in thread

* [RFC PATCH 45/45] KVM: arm/arm64: vgic-new: enable build
@ 2016-04-11 14:45       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-11 14:45 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 31/03/16 19:18, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:05:08AM +0000, Andre Przywara wrote:
>> Now that the new VGIC implementation has reached feature parity with
>> the old one, add the new files to the build system and add a Kconfig
>> option to switch between the two versions.
>> We set the default to the new version to get maximum test coverage,
>> in case people experience problems they can switch back to the old
>> behaviour if needed.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  arch/arm/kvm/Kconfig    |  7 +++++++
>>  arch/arm/kvm/Makefile   | 10 ++++++++++
>>  arch/arm64/kvm/Kconfig  |  7 +++++++
>>  arch/arm64/kvm/Makefile | 10 ++++++++++
>>  4 files changed, 34 insertions(+)
>>
>> diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
>> index 95a0005..02abfff 100644
>> --- a/arch/arm/kvm/Kconfig
>> +++ b/arch/arm/kvm/Kconfig
>> @@ -46,6 +46,13 @@ config KVM_ARM_HOST
>>  	---help---
>>  	  Provides host support for ARM processors.
>>  
>> +config KVM_NEW_VGIC
>> +	bool "New VGIC implementation"
>> +	depends on KVM
>> +	default y
>> +	---help---
>> +	  uses the new VGIC implementation
>> +
> 
> I had imagined we'd name it in the reverse, so the option would have
> been CONFIG_KVM_VGIC_LEGACY, but I guess the net effect should be the
> same, assuming most people just go with the default anyway.

I think originally the assumption was to make the old VGIC the default
in the beginning, but that changed later. By that time I considered it
too tedious to change all patches in this regard, so I just kept the old
symbol and semantic in.
Shouldn't matter, really, I guess there are arguments for both ways.

Cheers,
Andre.

>>  source drivers/vhost/Kconfig
>>  
>>  endif # VIRTUALIZATION
>> diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
>> index eb1bf43..aa7d724 100644
>> --- a/arch/arm/kvm/Makefile
>> +++ b/arch/arm/kvm/Makefile
>> @@ -21,7 +21,17 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp/
>>  obj-y += kvm-arm.o init.o interrupts.o
>>  obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
>>  obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
>> +
>> +ifeq ($(CONFIG_KVM_NEW_VGIC),y)
>> +obj-y += $(KVM)/arm/vgic/vgic.o
>> +obj-y += $(KVM)/arm/vgic/vgic_init.o
>> +obj-y += $(KVM)/arm/vgic/vgic_irqfd.o
>> +obj-y += $(KVM)/arm/vgic/vgic-v2.o
>> +obj-y += $(KVM)/arm/vgic/vgic_mmio.o
>> +obj-y += $(KVM)/arm/vgic/vgic_kvm_device.o
>> +else
>>  obj-y += $(KVM)/arm/vgic.o
>>  obj-y += $(KVM)/arm/vgic-v2.o
>>  obj-y += $(KVM)/arm/vgic-v2-emul.o
>> +endif
>>  obj-y += $(KVM)/arm/arch_timer.o
>> diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
>> index de7450d..3f0e1ce 100644
>> --- a/arch/arm64/kvm/Kconfig
>> +++ b/arch/arm64/kvm/Kconfig
>> @@ -55,6 +55,13 @@ config KVM_ARM_PMU
>>  	  Adds support for a virtual Performance Monitoring Unit (PMU) in
>>  	  virtual machines.
>>  
>> +config KVM_NEW_VGIC
>> +	bool "New VGIC implementation"
>> +	depends on KVM
>> +	default y
>> +        ---help---
>> +          uses the new VGIC implementation
>> +
>>  source drivers/vhost/Kconfig
>>  
>>  endif # VIRTUALIZATION
>> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
>> index 122cff4..2f5d431 100644
>> --- a/arch/arm64/kvm/Makefile
>> +++ b/arch/arm64/kvm/Makefile
>> @@ -20,10 +20,20 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
>>  
>> +ifeq ($(CONFIG_KVM_NEW_VGIC),y)
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_init.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_irqfd.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_mmio.o
>> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_kvm_device.o
>> +else
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
>> +endif
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
>>  kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
>> -- 
>> 2.7.3
>>
>> --
>> 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] 276+ messages in thread

* Re: [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
  2016-04-11 11:40       ` Andre Przywara
@ 2016-04-12 12:25         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 12:25 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Mon, Apr 11, 2016 at 12:40:01PM +0100, Andre Przywara wrote:
> On 31/03/16 10:47, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> Implement the functionality for syncing IRQs between our emulation
> >> and the list registers, which represent the guest's view of IRQs.
> >> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> >> which gets called on guest entry and exit.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  include/kvm/vgic/vgic.h     |   4 +
> >>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.h    |   4 +
> >>  4 files changed, 373 insertions(+)
> >>
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> index f32b284..986f23f 100644
> >> --- a/include/kvm/vgic/vgic.h
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> >>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> >>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> >>  
> >> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> >> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> >> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> >> +
> >>  /**
> >>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
> >>   *
> >> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >> index 0bf6f27..1cec423 100644
> >> --- a/virt/kvm/arm/vgic/vgic-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >> @@ -14,11 +14,172 @@
> >>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >>   */
> >>  
> >> +#include <linux/irqchip/arm-gic.h>
> >>  #include <linux/kvm.h>
> >>  #include <linux/kvm_host.h>
> >>  
> >>  #include "vgic.h"
> >>  
> >> +/*
> >> + * Call this function to convert a u64 value to an unsigned long * bitmask
> >> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> >> + *
> >> + * Warning: Calling this function may modify *val.
> >> + */
> >> +static unsigned long *u64_to_bitmask(u64 *val)
> >> +{
> >> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> >> +	*val = (*val >> 32) | (*val << 32);
> >> +#endif
> >> +	return (unsigned long *)val;
> >> +}
> >> +
> >> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> >> +		u64 eisr = cpuif->vgic_eisr;
> >> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> >> +		int lr;
> >> +
> >> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> >> +			struct vgic_irq *irq;
> >> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >> +
> >> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >> +
> >> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
> >> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> >> +
> >> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >> +
> >> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
> >> +			cpuif->vgic_elrsr |= 1ULL << lr;
> >> +		}
> >> +	}
> >> +
> >> +	/* check and disable underflow maintenance IRQ */
> >> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> >> +
> >> +	/*
> >> +	 * In the next iterations of the vcpu loop, if we sync the
> >> +	 * vgic state after flushing it, but before entering the guest
> >> +	 * (this happens for pending signals and vmid rollovers), then
> >> +	 * make sure we don't pick up any old maintenance interrupts
> >> +	 * here.
> >> +	 */
> >> +	cpuif->vgic_eisr = 0;
> >> +}
> >> +
> >> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> >> +}
> >> +
> >> +/*
> >> + * transfer the content of the LRs back into the corresponding ap_list:
> >> + * - active bit is transferred as is
> >> + * - pending bit is
> >> + *   - transferred as is in case of edge sensitive IRQs
> >> + *   - set to the line-level (resample time) for level sensitive IRQs
> >> + */
> >> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +	int lr;
> >> +
> >> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> >> +		u32 val = cpuif->vgic_lr[lr];
> >> +		u32 intid = val & GICH_LR_VIRTUALID;
> >> +		struct vgic_irq *irq;
> >> +
> >> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/* Always preserve the active bit */
> >> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> >> +
> >> +		/* Edge is the only case where we preserve the pending bit */
> >> +		if (irq->config == VGIC_CONFIG_EDGE &&
> >> +		    (val & GICH_LR_PENDING_BIT)) {
> >> +			irq->pending = true;
> >> +
> >> +			if (intid < VGIC_NR_SGIS) {
> >> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> >> +
> >> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> >> +				irq->source |= (1 << cpuid);
> >> +			}
> >> +		}
> >> +
> >> +		/* Clear soft pending state when level IRQs have been acked */
> >> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> >> +		    !(val & GICH_LR_PENDING_BIT)) {
> >> +			irq->soft_pending = false;
> >> +			irq->pending = irq->line_level;
> >> +		}
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +	}
> >> +}
> >> +
> >> +/*
> >> + * Populates the particular LR with the state of a given IRQ:
> >> + * - for an edge sensitive IRQ the pending state is reset in the struct
> >> + * - for a level sensitive IRQ the pending state value is unchanged;
> >> + *   it will be resampled on deactivation
> >> + *
> >> + * If irq is not NULL, the irq_lock must be hold already by the caller.
> >> + * If irq is NULL, the respective LR gets cleared.
> >> + */
> >> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> >> +{
> >> +	u32 val;
> >> +
> >> +	if (!irq) {
> >> +		val = 0;
> >> +		goto out;
> >> +	}
> >> +
> >> +	val = irq->intid;
> >> +
> >> +	if (irq->pending) {
> >> +		val |= GICH_LR_PENDING_BIT;
> >> +
> >> +		if (irq->config == VGIC_CONFIG_EDGE)
> >> +			irq->pending = false;
> >> +
> >> +		if (irq->intid < VGIC_NR_SGIS) {
> >> +			u32 src = ffs(irq->source);
> >> +
> >> +			BUG_ON(!src);
> >> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> >> +			irq->source &= ~(1 << (src - 1));
> >> +			if (irq->source)
> >> +				irq->pending = true;
> >> +		}
> >> +	}
> >> +
> >> +	if (irq->active)
> >> +		val |= GICH_LR_ACTIVE_BIT;
> >> +
> >> +	if (irq->hw) {
> >> +		val |= GICH_LR_HW;
> >> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> >> +	} else {
> >> +		if (irq->config == VGIC_CONFIG_LEVEL)
> >> +			val |= GICH_LR_EOI;
> >> +	}
> > 
> > shouldn't we start writing the priority here (and in the GICv3 version)?
> > 
> > (which has the fun consequence of having to compare priorities against
> > the virtual priority filter in PATCH 11).
> 
> This is probably true.
> 
> I just feel I am getting overwhelmed with the change requests, can one
> of you (Marc, Christoffer) fix this? Just use the existing code base, I
> can rebase any change into the new tree.

Sure, I'll send patches based on your next iteration of this series.
Can you add a TODO: Christoffer to implement this here?

> 
> The priority field in the v2 LR is only 5 bits long, is that covered by
> the virtual priority filter you mentioned?
> 
Not sure what you're asking, but I think we can deal with this once I
send my patches and you review them ;)

-Christoffer

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

* [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush
@ 2016-04-12 12:25         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 12:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 11, 2016 at 12:40:01PM +0100, Andre Przywara wrote:
> On 31/03/16 10:47, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:32AM +0000, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> Implement the functionality for syncing IRQs between our emulation
> >> and the list registers, which represent the guest's view of IRQs.
> >> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> >> which gets called on guest entry and exit.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  include/kvm/vgic/vgic.h     |   4 +
> >>  virt/kvm/arm/vgic/vgic-v2.c | 161 ++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.c    | 204 ++++++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.h    |   4 +
> >>  4 files changed, 373 insertions(+)
> >>
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> index f32b284..986f23f 100644
> >> --- a/include/kvm/vgic/vgic.h
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -187,6 +187,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> >>  #define vgic_valid_spi(k,i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> >>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> >>  
> >> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> >> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> >> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> >> +
> >>  /**
> >>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
> >>   *
> >> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >> index 0bf6f27..1cec423 100644
> >> --- a/virt/kvm/arm/vgic/vgic-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >> @@ -14,11 +14,172 @@
> >>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >>   */
> >>  
> >> +#include <linux/irqchip/arm-gic.h>
> >>  #include <linux/kvm.h>
> >>  #include <linux/kvm_host.h>
> >>  
> >>  #include "vgic.h"
> >>  
> >> +/*
> >> + * Call this function to convert a u64 value to an unsigned long * bitmask
> >> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> >> + *
> >> + * Warning: Calling this function may modify *val.
> >> + */
> >> +static unsigned long *u64_to_bitmask(u64 *val)
> >> +{
> >> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> >> +	*val = (*val >> 32) | (*val << 32);
> >> +#endif
> >> +	return (unsigned long *)val;
> >> +}
> >> +
> >> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> >> +		u64 eisr = cpuif->vgic_eisr;
> >> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> >> +		int lr;
> >> +
> >> +		for_each_set_bit(lr, eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> >> +			struct vgic_irq *irq;
> >> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >> +
> >> +			irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >> +
> >> +			WARN_ON(irq->config == VGIC_CONFIG_EDGE);
> >> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> >> +
> >> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >> +
> >> +			cpuif->vgic_lr[lr] &= ~GICH_LR_STATE; /* Useful?? */
> >> +			cpuif->vgic_elrsr |= 1ULL << lr;
> >> +		}
> >> +	}
> >> +
> >> +	/* check and disable underflow maintenance IRQ */
> >> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> >> +
> >> +	/*
> >> +	 * In the next iterations of the vcpu loop, if we sync the
> >> +	 * vgic state after flushing it, but before entering the guest
> >> +	 * (this happens for pending signals and vmid rollovers), then
> >> +	 * make sure we don't pick up any old maintenance interrupts
> >> +	 * here.
> >> +	 */
> >> +	cpuif->vgic_eisr = 0;
> >> +}
> >> +
> >> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> >> +}
> >> +
> >> +/*
> >> + * transfer the content of the LRs back into the corresponding ap_list:
> >> + * - active bit is transferred as is
> >> + * - pending bit is
> >> + *   - transferred as is in case of edge sensitive IRQs
> >> + *   - set to the line-level (resample time) for level sensitive IRQs
> >> + */
> >> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +	int lr;
> >> +
> >> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> >> +		u32 val = cpuif->vgic_lr[lr];
> >> +		u32 intid = val & GICH_LR_VIRTUALID;
> >> +		struct vgic_irq *irq;
> >> +
> >> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/* Always preserve the active bit */
> >> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> >> +
> >> +		/* Edge is the only case where we preserve the pending bit */
> >> +		if (irq->config == VGIC_CONFIG_EDGE &&
> >> +		    (val & GICH_LR_PENDING_BIT)) {
> >> +			irq->pending = true;
> >> +
> >> +			if (intid < VGIC_NR_SGIS) {
> >> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> >> +
> >> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> >> +				irq->source |= (1 << cpuid);
> >> +			}
> >> +		}
> >> +
> >> +		/* Clear soft pending state when level IRQs have been acked */
> >> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> >> +		    !(val & GICH_LR_PENDING_BIT)) {
> >> +			irq->soft_pending = false;
> >> +			irq->pending = irq->line_level;
> >> +		}
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +	}
> >> +}
> >> +
> >> +/*
> >> + * Populates the particular LR with the state of a given IRQ:
> >> + * - for an edge sensitive IRQ the pending state is reset in the struct
> >> + * - for a level sensitive IRQ the pending state value is unchanged;
> >> + *   it will be resampled on deactivation
> >> + *
> >> + * If irq is not NULL, the irq_lock must be hold already by the caller.
> >> + * If irq is NULL, the respective LR gets cleared.
> >> + */
> >> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> >> +{
> >> +	u32 val;
> >> +
> >> +	if (!irq) {
> >> +		val = 0;
> >> +		goto out;
> >> +	}
> >> +
> >> +	val = irq->intid;
> >> +
> >> +	if (irq->pending) {
> >> +		val |= GICH_LR_PENDING_BIT;
> >> +
> >> +		if (irq->config == VGIC_CONFIG_EDGE)
> >> +			irq->pending = false;
> >> +
> >> +		if (irq->intid < VGIC_NR_SGIS) {
> >> +			u32 src = ffs(irq->source);
> >> +
> >> +			BUG_ON(!src);
> >> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> >> +			irq->source &= ~(1 << (src - 1));
> >> +			if (irq->source)
> >> +				irq->pending = true;
> >> +		}
> >> +	}
> >> +
> >> +	if (irq->active)
> >> +		val |= GICH_LR_ACTIVE_BIT;
> >> +
> >> +	if (irq->hw) {
> >> +		val |= GICH_LR_HW;
> >> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> >> +	} else {
> >> +		if (irq->config == VGIC_CONFIG_LEVEL)
> >> +			val |= GICH_LR_EOI;
> >> +	}
> > 
> > shouldn't we start writing the priority here (and in the GICv3 version)?
> > 
> > (which has the fun consequence of having to compare priorities against
> > the virtual priority filter in PATCH 11).
> 
> This is probably true.
> 
> I just feel I am getting overwhelmed with the change requests, can one
> of you (Marc, Christoffer) fix this? Just use the existing code base, I
> can rebase any change into the new tree.

Sure, I'll send patches based on your next iteration of this series.
Can you add a TODO: Christoffer to implement this here?

> 
> The priority field in the v2 LR is only 5 bits long, is that covered by
> the virtual priority filter you mentioned?
> 
Not sure what you're asking, but I think we can deal with this once I
send my patches and you review them ;)

-Christoffer

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

* Re: [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-04-11 10:53       ` Andre Przywara
@ 2016-04-12 12:50         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 12:50 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, linux-arm-kernel, kvmarm, kvm

On Mon, Apr 11, 2016 at 11:53:21AM +0100, Andre Przywara wrote:
> Hi Christoffer,
> 
> On 31/03/16 10:08, Christoffer Dall wrote:
> > Hi Andre,
> > 
> > [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
> > 
> > On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
> >> We register each register group of the distributor and redistributors
> >> as separate regions of the kvm-io-bus framework. This way calls get
> >> directly handed over to the actual handler.
> >> This puts a lot more regions into kvm-io-bus than what we use at the
> >> moment on other architectures, so we will probably need to revisit the
> >> implementation of the framework later to be more efficient.
> > 
> > Looking more carefully at the KVM IO bus stuff, it looks like it is
> > indeed designed to be a *per device* thing you register, not a *per
> > register* thing.
> > 
> > My comments to Vladimir's bug report notwithstanding, there's still a
> > choice here to:
> > 
> > 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> > 
> > 2) Build a KVM architectureal generic framework on top of the IO bus
> > framework to handle individual register regions.
> > 
> > 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> > and handle the individual register region business locally within the
> > arm/vgic code.
> > 
> > 
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> ---
> >>  include/kvm/vgic/vgic.h       |   9 ++
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
> >>  3 files changed, 250 insertions(+)
> >>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
> >>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
> >>
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> index 2ce9b4a..a8262c7 100644
> >> --- a/include/kvm/vgic/vgic.h
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -106,6 +106,12 @@ struct vgic_irq {
> >>  	enum vgic_irq_config config;	/* Level or edge */
> >>  };
> >>  
> >> +struct vgic_io_device {
> >> +	gpa_t base_addr;
> >> +	struct kvm_vcpu *redist_vcpu;
> >> +	struct kvm_io_device dev;
> >> +};
> >> +
> >>  struct vgic_dist {
> >>  	bool			in_kernel;
> >>  	bool			ready;
> >> @@ -132,6 +138,9 @@ struct vgic_dist {
> >>  	u32			enabled;
> >>  
> >>  	struct vgic_irq		*spis;
> >> +
> >> +	struct vgic_io_device	*dist_iodevs;
> >> +	struct vgic_io_device	*redist_iodevs;
> >>  };
> >>  
> >>  struct vgic_v2_cpu_if {
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> new file mode 100644
> >> index 0000000..26c46e7
> >> --- /dev/null
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -0,0 +1,194 @@
> >> +/*
> >> + * VGIC MMIO handling functions
> >> + *
> >> + * 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.
> >> + */
> >> +
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_host.h>
> >> +#include <kvm/iodev.h>
> >> +#include <kvm/vgic/vgic.h>
> >> +#include <linux/bitops.h>
> >> +#include <linux/irqchip/arm-gic.h>
> >> +
> >> +#include "vgic.h"
> >> +#include "vgic_mmio.h"
> >> +
> >> +void write_mask32(u32 value, int offset, int len, void *val)
> >> +{
> >> +	value = cpu_to_le32(value) >> (offset * 8);
> >> +	memcpy(val, &value, len);
> >> +}
> >> +
> >> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
> >> +{
> >> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
> >> +	memcpy((char *)&origvalue + (offset * 8), val, len);
> >> +	return origvalue;
> >> +}
> >> +
> >> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> >> +void write_mask64(u64 value, int offset, int len, void *val)
> >> +{
> >> +	value = cpu_to_le64(value) >> (offset * 8);
> >> +	memcpy(val, &value, len);
> >> +}
> >> +
> >> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
> > 
> > I'm confuses in general.  Can you explain what these mask functions do
> > overall at some higher level?
> 
> They do what you already guessed: take care about masking and endianness.
> 
> > I also keep having a feeling that mixing endianness stuff into the
> > emulation code itself is the wrong way to go about it.
> 
> I agree.
> 
> >  The emulation
> > code should just deal with register values of varying length and the
> > interface to the VGIC should abstract all endianness nonsense for us,
> > but I also think I've lost this argument some time in the past.  Sigh.

I tend to agree with this.  Who did you loose this argument against and
do you have a pointer?

> > 
> > But, is the maximum read/write unit for any MMIO access not a 64-bit
> > value?  So why can't we let the VGIC emulation code simply take/return a
> > u64 which is then masked off/morphed into the right endianness outside
> > the VGIC code?
> 
> The main problem is that the interface for kvm_io_bus is (int len, void
> *val).

That could be solved by always just doing a (u64) conversion on the
caller/receiver side.  E.g.

int vgic_handle_mmio_access(..., int len, void *val, bool is_write)
{
	u64 data;

	if (unsupported_vgic_len(len))
		return -ENXIO;

	if (is_write)
		data = mmio_read_buf(val, len);

	// data is now just some data of some lenght in a typed register

	call_range_handler(vcpu, &data, len, ...);

	if (!is_write)
		mmio_write_buf(val, len, data);
}

(and share the mmio_ functions in a header file between mmio.c and
consumers of the packed data).

The idea would be that the gic is just emulation code in C, which can be
compiled to some endianness, and we really don't care about how it's
physically stored in memory.



> And since the guest's MMIO access can be of different length, we need to
> take care of this in any case (since we need to know how many IRQs we
> need to update). So we cannot get rid of the length parameter.

no we cannot, but we can use a typed pointer instead of a void pointer
everywhere in the vgic code, since the max access we're going to support
is 64 bits.

> I guess what we could do is to either:
> a) Declare the VGIC as purely little endian (which it really is, AFAIK).
> We care about the necessary endianness conversion in mmio.c before
> invoking the kvm_io_bus framework. But that means that we need to deal
> with the _host's_ endianness in the VGIC emulation.
> I think this is very close to what we currently do.    OR
> b) Declare our VGIC emulation as always using the host's endianess. We
> wouldn't need to care about endianness in the VGIC code anymore (is that
> actually true?) We convert the MMIO traps (which are little endian
> always) into the host's endianness before passing it on to kvm-io-bus.
> 
> I just see that this probably adds more to the confusion, oh well...

No, it doesn't add anymore confusion.  I think option (b) is what we
should do, unless it's not possible for some reason that I fail to
realize at this very moment.

If all your pointers in the vgic emulation code are always typed, then I
don't see why you'd have to worry about endianness anywhere?

The only place we should worry about endianness is the
vcpu_data_guest_to_host() and vcpu_data_host_to_guest() functions.
Doing it anywhere else as well is an indication that we're doing
something wrong.


Thanks,
-Christoffer

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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-04-12 12:50         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 12:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 11, 2016 at 11:53:21AM +0100, Andre Przywara wrote:
> Hi Christoffer,
> 
> On 31/03/16 10:08, Christoffer Dall wrote:
> > Hi Andre,
> > 
> > [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
> > 
> > On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
> >> We register each register group of the distributor and redistributors
> >> as separate regions of the kvm-io-bus framework. This way calls get
> >> directly handed over to the actual handler.
> >> This puts a lot more regions into kvm-io-bus than what we use at the
> >> moment on other architectures, so we will probably need to revisit the
> >> implementation of the framework later to be more efficient.
> > 
> > Looking more carefully at the KVM IO bus stuff, it looks like it is
> > indeed designed to be a *per device* thing you register, not a *per
> > register* thing.
> > 
> > My comments to Vladimir's bug report notwithstanding, there's still a
> > choice here to:
> > 
> > 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> > 
> > 2) Build a KVM architectureal generic framework on top of the IO bus
> > framework to handle individual register regions.
> > 
> > 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> > and handle the individual register region business locally within the
> > arm/vgic code.
> > 
> > 
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> ---
> >>  include/kvm/vgic/vgic.h       |   9 ++
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
> >>  3 files changed, 250 insertions(+)
> >>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
> >>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
> >>
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> index 2ce9b4a..a8262c7 100644
> >> --- a/include/kvm/vgic/vgic.h
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -106,6 +106,12 @@ struct vgic_irq {
> >>  	enum vgic_irq_config config;	/* Level or edge */
> >>  };
> >>  
> >> +struct vgic_io_device {
> >> +	gpa_t base_addr;
> >> +	struct kvm_vcpu *redist_vcpu;
> >> +	struct kvm_io_device dev;
> >> +};
> >> +
> >>  struct vgic_dist {
> >>  	bool			in_kernel;
> >>  	bool			ready;
> >> @@ -132,6 +138,9 @@ struct vgic_dist {
> >>  	u32			enabled;
> >>  
> >>  	struct vgic_irq		*spis;
> >> +
> >> +	struct vgic_io_device	*dist_iodevs;
> >> +	struct vgic_io_device	*redist_iodevs;
> >>  };
> >>  
> >>  struct vgic_v2_cpu_if {
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> new file mode 100644
> >> index 0000000..26c46e7
> >> --- /dev/null
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -0,0 +1,194 @@
> >> +/*
> >> + * VGIC MMIO handling functions
> >> + *
> >> + * 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.
> >> + */
> >> +
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_host.h>
> >> +#include <kvm/iodev.h>
> >> +#include <kvm/vgic/vgic.h>
> >> +#include <linux/bitops.h>
> >> +#include <linux/irqchip/arm-gic.h>
> >> +
> >> +#include "vgic.h"
> >> +#include "vgic_mmio.h"
> >> +
> >> +void write_mask32(u32 value, int offset, int len, void *val)
> >> +{
> >> +	value = cpu_to_le32(value) >> (offset * 8);
> >> +	memcpy(val, &value, len);
> >> +}
> >> +
> >> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
> >> +{
> >> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
> >> +	memcpy((char *)&origvalue + (offset * 8), val, len);
> >> +	return origvalue;
> >> +}
> >> +
> >> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> >> +void write_mask64(u64 value, int offset, int len, void *val)
> >> +{
> >> +	value = cpu_to_le64(value) >> (offset * 8);
> >> +	memcpy(val, &value, len);
> >> +}
> >> +
> >> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
> > 
> > I'm confuses in general.  Can you explain what these mask functions do
> > overall at some higher level?
> 
> They do what you already guessed: take care about masking and endianness.
> 
> > I also keep having a feeling that mixing endianness stuff into the
> > emulation code itself is the wrong way to go about it.
> 
> I agree.
> 
> >  The emulation
> > code should just deal with register values of varying length and the
> > interface to the VGIC should abstract all endianness nonsense for us,
> > but I also think I've lost this argument some time in the past.  Sigh.

I tend to agree with this.  Who did you loose this argument against and
do you have a pointer?

> > 
> > But, is the maximum read/write unit for any MMIO access not a 64-bit
> > value?  So why can't we let the VGIC emulation code simply take/return a
> > u64 which is then masked off/morphed into the right endianness outside
> > the VGIC code?
> 
> The main problem is that the interface for kvm_io_bus is (int len, void
> *val).

That could be solved by always just doing a (u64) conversion on the
caller/receiver side.  E.g.

int vgic_handle_mmio_access(..., int len, void *val, bool is_write)
{
	u64 data;

	if (unsupported_vgic_len(len))
		return -ENXIO;

	if (is_write)
		data = mmio_read_buf(val, len);

	// data is now just some data of some lenght in a typed register

	call_range_handler(vcpu, &data, len, ...);

	if (!is_write)
		mmio_write_buf(val, len, data);
}

(and share the mmio_ functions in a header file between mmio.c and
consumers of the packed data).

The idea would be that the gic is just emulation code in C, which can be
compiled to some endianness, and we really don't care about how it's
physically stored in memory.



> And since the guest's MMIO access can be of different length, we need to
> take care of this in any case (since we need to know how many IRQs we
> need to update). So we cannot get rid of the length parameter.

no we cannot, but we can use a typed pointer instead of a void pointer
everywhere in the vgic code, since the max access we're going to support
is 64 bits.

> I guess what we could do is to either:
> a) Declare the VGIC as purely little endian (which it really is, AFAIK).
> We care about the necessary endianness conversion in mmio.c before
> invoking the kvm_io_bus framework. But that means that we need to deal
> with the _host's_ endianness in the VGIC emulation.
> I think this is very close to what we currently do.    OR
> b) Declare our VGIC emulation as always using the host's endianess. We
> wouldn't need to care about endianness in the VGIC code anymore (is that
> actually true?) We convert the MMIO traps (which are little endian
> always) into the host's endianness before passing it on to kvm-io-bus.
> 
> I just see that this probably adds more to the confusion, oh well...

No, it doesn't add anymore confusion.  I think option (b) is what we
should do, unless it's not possible for some reason that I fail to
realize at this very moment.

If all your pointers in the vgic emulation code are always typed, then I
don't see why you'd have to worry about endianness anywhere?

The only place we should worry about endianness is the
vcpu_data_guest_to_host() and vcpu_data_host_to_guest() functions.
Doing it anywhere else as well is an indication that we're doing
something wrong.


Thanks,
-Christoffer

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

* Re: [RFC PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface
  2016-04-11 11:09       ` Andre Przywara
@ 2016-04-12 12:52         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 12:52 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Mon, Apr 11, 2016 at 12:09:49PM +0100, Andre Przywara wrote:
> Hej,
> 
> On 31/03/16 10:24, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:36AM +0000, Andre Przywara wrote:
> >> Userland can access the emulated GIC to save and restore its state
> >> for initialization or migration purposes.
> >> The kvm_io_bus API requires an absolute gpa, which does not fit the
> >> KVM_DEV_ARM_VGIC_GRP_DIST_REGS user API, that only provides relative
> >> offsets. So we explicitly iterate our register list to connect
> >> userland to the VGIC.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> >> ---
> >>  virt/kvm/arm/vgic/vgic.h      |  2 ++
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 45 +++++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 47 insertions(+)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> >> index 53730ba..a462e2b 100644
> >> --- a/virt/kvm/arm/vgic/vgic.h
> >> +++ b/virt/kvm/arm/vgic/vgic.h
> >> @@ -25,6 +25,8 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> >>  void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> >>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> >>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> >> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> >> +			int offset, int len, void *val);
> >>  
> >>  #ifdef CONFIG_KVM_ARM_VGIC_V3
> >>  void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> index 26c46e7..e1fd17f 100644
> >> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -113,6 +113,51 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
> >>  };
> >>  
> >> +/*
> >> + * Using kvm_io_bus_* to access GIC registers directly from userspace does
> >> + * not work, since we would need the absolute IPA address of the register
> >> + * in question, but the userland interface only provides relative offsets.
> >> + * So we provide our own dispatcher function for that purpose here.
> >> + */
> >> +static int vgic_mmio_access(struct kvm_vcpu *vcpu,
> >> +			    struct vgic_register_region *region, int nr_regions,
> >> +			    bool is_write, int offset, int len, void *val)
> >> +{
> > 
> > I suspect this is going to get rewored based on previous discussions
> > with the IO api...
> > 
> >> +	int i;
> >> +	struct vgic_io_device dev;
> >> +
> >> +	for (i = 0; i < nr_regions; i++) {
> >> +		int reg_size = region[i].len;
> >> +
> >> +		if (!reg_size)
> >> +			reg_size = (region[i].bits_per_irq * 1024) / 8;
> >> +
> >> +		if ((offset < region[i].reg_offset) ||
> >> +		    (offset + len > region[i].reg_offset + reg_size))
> >> +			continue;
> >> +
> >> +		dev.base_addr	= region[i].reg_offset;
> >> +		dev.redist_vcpu	= vcpu;
> >> +
> >> +		if (is_write)
> >> +			return region[i].ops.write(vcpu, &dev.dev,
> >> +						   offset, len, val);
> >> +		else
> >> +			return region[i].ops.read(vcpu, &dev.dev,
> >> +						  offset, len, val);
> >> +	}
> >> +
> >> +	return -ENODEV;
> >> +}
> >> +
> >> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> >> +			int offset, int len, void *val)
> >> +{
> >> +	return vgic_mmio_access(vcpu, vgic_v2_dist_registers,
> >> +				ARRAY_SIZE(vgic_v2_dist_registers),
> >> +				is_write, offset, len, val);
> >> +}
> >> +
> > 
> > this makes me wonder if the v2 region declarations and functions like
> > this should go in a separate file?  vgic/mmio-v2.c ?
> 
> But we actually share a lot of functions like all the PENDING, ENABLED,
> ACTIVE, PRIORITY, IGROUP register handlers. So we would need to export
> them in order to be used by both the v2 and v3 emulation. This is what I
> did for the existing v3 emulation, but I didn't like it very much.
> Now we keep all of this private and static, both the handler functions
> and the structures declaring the respective register layout.
> I found this more appropriate now that v2 and v3 emulation are developed
> hand in hand.
> I see that the file gets pretty big, but it's still only roughly half
> the size of the old vgic.c and also smaller than the combined old
> vgic-v2-emul.c and vgic-v3-emul.c.
> 
> So I guess those 37K are just the price we need to pay for the beast
> that the GIC actually is.
> 
ok, that's a convincing argument.

Thanks,
-Christoffer

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

* [RFC PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface
@ 2016-04-12 12:52         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 12:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 11, 2016 at 12:09:49PM +0100, Andre Przywara wrote:
> Hej,
> 
> On 31/03/16 10:24, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:36AM +0000, Andre Przywara wrote:
> >> Userland can access the emulated GIC to save and restore its state
> >> for initialization or migration purposes.
> >> The kvm_io_bus API requires an absolute gpa, which does not fit the
> >> KVM_DEV_ARM_VGIC_GRP_DIST_REGS user API, that only provides relative
> >> offsets. So we explicitly iterate our register list to connect
> >> userland to the VGIC.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> >> ---
> >>  virt/kvm/arm/vgic/vgic.h      |  2 ++
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 45 +++++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 47 insertions(+)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> >> index 53730ba..a462e2b 100644
> >> --- a/virt/kvm/arm/vgic/vgic.h
> >> +++ b/virt/kvm/arm/vgic/vgic.h
> >> @@ -25,6 +25,8 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> >>  void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> >>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> >>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> >> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> >> +			int offset, int len, void *val);
> >>  
> >>  #ifdef CONFIG_KVM_ARM_VGIC_V3
> >>  void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> index 26c46e7..e1fd17f 100644
> >> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -113,6 +113,51 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
> >>  };
> >>  
> >> +/*
> >> + * Using kvm_io_bus_* to access GIC registers directly from userspace does
> >> + * not work, since we would need the absolute IPA address of the register
> >> + * in question, but the userland interface only provides relative offsets.
> >> + * So we provide our own dispatcher function for that purpose here.
> >> + */
> >> +static int vgic_mmio_access(struct kvm_vcpu *vcpu,
> >> +			    struct vgic_register_region *region, int nr_regions,
> >> +			    bool is_write, int offset, int len, void *val)
> >> +{
> > 
> > I suspect this is going to get rewored based on previous discussions
> > with the IO api...
> > 
> >> +	int i;
> >> +	struct vgic_io_device dev;
> >> +
> >> +	for (i = 0; i < nr_regions; i++) {
> >> +		int reg_size = region[i].len;
> >> +
> >> +		if (!reg_size)
> >> +			reg_size = (region[i].bits_per_irq * 1024) / 8;
> >> +
> >> +		if ((offset < region[i].reg_offset) ||
> >> +		    (offset + len > region[i].reg_offset + reg_size))
> >> +			continue;
> >> +
> >> +		dev.base_addr	= region[i].reg_offset;
> >> +		dev.redist_vcpu	= vcpu;
> >> +
> >> +		if (is_write)
> >> +			return region[i].ops.write(vcpu, &dev.dev,
> >> +						   offset, len, val);
> >> +		else
> >> +			return region[i].ops.read(vcpu, &dev.dev,
> >> +						  offset, len, val);
> >> +	}
> >> +
> >> +	return -ENODEV;
> >> +}
> >> +
> >> +int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> >> +			int offset, int len, void *val)
> >> +{
> >> +	return vgic_mmio_access(vcpu, vgic_v2_dist_registers,
> >> +				ARRAY_SIZE(vgic_v2_dist_registers),
> >> +				is_write, offset, len, val);
> >> +}
> >> +
> > 
> > this makes me wonder if the v2 region declarations and functions like
> > this should go in a separate file?  vgic/mmio-v2.c ?
> 
> But we actually share a lot of functions like all the PENDING, ENABLED,
> ACTIVE, PRIORITY, IGROUP register handlers. So we would need to export
> them in order to be used by both the v2 and v3 emulation. This is what I
> did for the existing v3 emulation, but I didn't like it very much.
> Now we keep all of this private and static, both the handler functions
> and the structures declaring the respective register layout.
> I found this more appropriate now that v2 and v3 emulation are developed
> hand in hand.
> I see that the file gets pretty big, but it's still only roughly half
> the size of the old vgic.c and also smaller than the combined old
> vgic-v2-emul.c and vgic-v3-emul.c.
> 
> So I guess those 37K are just the price we need to pay for the beast
> that the GIC actually is.
> 
ok, that's a convincing argument.

Thanks,
-Christoffer

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

* Re: [RFC PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-04-11 11:23       ` Andre Przywara
@ 2016-04-12 12:55         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 12:55 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Mon, Apr 11, 2016 at 12:23:25PM +0100, Andre Przywara wrote:
> On 31/03/16 10:27, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:37AM +0000, Andre Przywara wrote:
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic.h      |  3 +++
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 49 ++++++++++++++++++++++++++++++++++++++++++-
> >>  2 files changed, 51 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> >> index a462e2b..57aea8f 100644
> >> --- a/virt/kvm/arm/vgic/vgic.h
> >> +++ b/virt/kvm/arm/vgic/vgic.h
> >> @@ -16,6 +16,9 @@
> >>  #ifndef __KVM_ARM_VGIC_NEW_H__
> >>  #define __KVM_ARM_VGIC_NEW_H__
> >>  
> >> +#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
> >> +#define IMPLEMENTER_ARM		0x43b
> >> +
> >>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>  			      u32 intid);
> >>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> index e1fd17f..e62366e 100644
> >> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -82,9 +82,56 @@ static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
> >>  	return 0;
> >>  }
> >>  
> >> +static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
> >> +				  struct kvm_io_device *this,
> >> +				  gpa_t addr, int len, void *val)
> >> +{
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	u32 value;
> >> +
> >> +	switch ((addr - iodev->base_addr) & ~3) {
> >> +	case 0x0:
> >> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
> >> +		break;
> >> +	case 0x4:
> >> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> >> +		value = (value >> 5) - 1;
> >> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
> >> +		break;
> >> +	case 0x8:
> >> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> >> +		break;
> >> +	default:
> >> +		return 0;
> >> +	}
> >> +
> >> +	write_mask32(value, addr & 3, len, val);
> >> +	return 0;
> >> +}
> >> +
> >> +static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> >> +				   struct kvm_io_device *this,
> >> +				   gpa_t addr, int len, const void *val)
> >> +{
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	/*
> >> +	 * GICD_TYPER and GICD_IIDR are read-only, the upper three bytes of
> >> +	 * GICD_CTLR are reserved.
> >> +	 */
> >> +	if (addr - iodev->base_addr >= 1)
> >> +		return 0;
> >> +
> >> +	vcpu->kvm->arch.vgic.enabled = (*(u32 *)val) ? true : false;
> >> +	/* TODO: is there anything to trigger at this point? */
> > 
> > I guess we should actually check if the vgic is enabled in PATH 11, and
> > we should kick all VCPUs (or at least those with something pending) if
> > we went from disabled to enabled?
> > 
> > We should probably also check this in the sync function...
> > 
> > Or do we enforce this enabled bool somewhere else that I missed?
> 
> Good point, I guess in the moment we just rely upon the VGIC being
> enabled very early and never getting disabled.
> So I will introduce checks in kvm_vgic_vcpu_pending_irq and the flush
> function (which is called before entering the guest, I guess this is
> what you meant with the "sync function"?), also kick all (?) VCPUs here
> in case we enable the GIC.

I'm not sure what I meant by the sync function, perhaps I meant queue
function really (I usually don't have troubles telling sync/flush
apart).

In any case, dealing with the enabled setting has consequences pretty
much all over I think.

Side question: Can you EOI an active interrupt even if you disabled the
VGIC?  I think the spec only says that the enabled bit prevents the GIC
from forwarding pending interrupts to the CPU interface or something
like that?

Thanks,
-Christoffer

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

* [RFC PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-04-12 12:55         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 12:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 11, 2016 at 12:23:25PM +0100, Andre Przywara wrote:
> On 31/03/16 10:27, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:37AM +0000, Andre Przywara wrote:
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic.h      |  3 +++
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 49 ++++++++++++++++++++++++++++++++++++++++++-
> >>  2 files changed, 51 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> >> index a462e2b..57aea8f 100644
> >> --- a/virt/kvm/arm/vgic/vgic.h
> >> +++ b/virt/kvm/arm/vgic/vgic.h
> >> @@ -16,6 +16,9 @@
> >>  #ifndef __KVM_ARM_VGIC_NEW_H__
> >>  #define __KVM_ARM_VGIC_NEW_H__
> >>  
> >> +#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
> >> +#define IMPLEMENTER_ARM		0x43b
> >> +
> >>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>  			      u32 intid);
> >>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> index e1fd17f..e62366e 100644
> >> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -82,9 +82,56 @@ static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
> >>  	return 0;
> >>  }
> >>  
> >> +static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
> >> +				  struct kvm_io_device *this,
> >> +				  gpa_t addr, int len, void *val)
> >> +{
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	u32 value;
> >> +
> >> +	switch ((addr - iodev->base_addr) & ~3) {
> >> +	case 0x0:
> >> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
> >> +		break;
> >> +	case 0x4:
> >> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> >> +		value = (value >> 5) - 1;
> >> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
> >> +		break;
> >> +	case 0x8:
> >> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> >> +		break;
> >> +	default:
> >> +		return 0;
> >> +	}
> >> +
> >> +	write_mask32(value, addr & 3, len, val);
> >> +	return 0;
> >> +}
> >> +
> >> +static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> >> +				   struct kvm_io_device *this,
> >> +				   gpa_t addr, int len, const void *val)
> >> +{
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	/*
> >> +	 * GICD_TYPER and GICD_IIDR are read-only, the upper three bytes of
> >> +	 * GICD_CTLR are reserved.
> >> +	 */
> >> +	if (addr - iodev->base_addr >= 1)
> >> +		return 0;
> >> +
> >> +	vcpu->kvm->arch.vgic.enabled = (*(u32 *)val) ? true : false;
> >> +	/* TODO: is there anything to trigger at this point? */
> > 
> > I guess we should actually check if the vgic is enabled in PATH 11, and
> > we should kick all VCPUs (or at least those with something pending) if
> > we went from disabled to enabled?
> > 
> > We should probably also check this in the sync function...
> > 
> > Or do we enforce this enabled bool somewhere else that I missed?
> 
> Good point, I guess in the moment we just rely upon the VGIC being
> enabled very early and never getting disabled.
> So I will introduce checks in kvm_vgic_vcpu_pending_irq and the flush
> function (which is called before entering the guest, I guess this is
> what you meant with the "sync function"?), also kick all (?) VCPUs here
> in case we enable the GIC.

I'm not sure what I meant by the sync function, perhaps I meant queue
function really (I usually don't have troubles telling sync/flush
apart).

In any case, dealing with the enabled setting has consequences pretty
much all over I think.

Side question: Can you EOI an active interrupt even if you disabled the
VGIC?  I think the spec only says that the enabled bit prevents the GIC
from forwarding pending interrupts to the CPU interface or something
like that?

Thanks,
-Christoffer

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

* Re: [RFC PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
  2016-04-11 11:31       ` Andre Przywara
@ 2016-04-12 13:10         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 13:10 UTC (permalink / raw)
  To: Andre Przywara, j; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Mon, Apr 11, 2016 at 12:31:32PM +0100, Andre Przywara wrote:
> On 31/03/16 10:35, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:39AM +0000, Andre Przywara wrote:
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 87 ++++++++++++++++++++++++++++++++++++++++++-
> >>  1 file changed, 85 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> index 0688a69..8514f92 100644
> >> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -206,6 +206,89 @@ static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
> >>  	return 0;
> >>  }
> >>  
> >> +static int vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
> >> +				  struct kvm_io_device *this,
> >> +				  gpa_t addr, int len, void *val)
> >> +{
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	u32 intid = (addr - iodev->base_addr) * 8;
> >> +	u32 value = 0;
> >> +	int i;
> >> +
> >> +	if (iodev->redist_vcpu)
> >> +		vcpu = iodev->redist_vcpu;
> >> +
> >> +	/* Loop over all IRQs affected by this read */
> >> +	for (i = 0; i < len * 8; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +		if (irq->pending)
> >> +			value |= (1U << i);
> >> +		spin_unlock(&irq->irq_lock);
> > 
> > here there clearly is no need to take the lock (because a bool read is
> > atomic), but that should be explained in a one-line comment.
> 
> Is that really true? Isn't it that another lock holder expects full
> control over the IRQ struct, including the freedom to change values at
> will without caring about other observers?

Consider the following three cases, assuming pending is clear in the
initial state:

Case 1:
	CPU A			CPU B
	-----			-----
	read pending
				lock irq
				set pending
				unlock irq

Case 2:
	CPU A			CPU B
	-----			-----
				lock irq
	read pending
				set pending
				unlock irq


Case 3:
	CPU A			CPU B
	-----			-----
				lock irq
				set pending
				unlock irq
	read pending


The only effect of adding a lock/unlock around the read_pending()
operation is to force case 2 to be equivalent to case 3, but case 1
could still happen, so this just boils down to observing the value
before or after the write, both of which are fine.

If there were weird side effect from reading this value, or even getting
to the struct would depend on other things CPU B could do while holding
the lock, it would be a different story, but here I'm faily certain you
don't need the lock.

> I might be too paranoid here, but I think I explicitly added the lock
> here for a reason (which I don't remember anymore, sadly).
> 

Can you can find an example where something breaks without holding the
lock here?

Thanks,
-Christoffer

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

* [RFC PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
@ 2016-04-12 13:10         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 13:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 11, 2016 at 12:31:32PM +0100, Andre Przywara wrote:
> On 31/03/16 10:35, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:39AM +0000, Andre Przywara wrote:
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 87 ++++++++++++++++++++++++++++++++++++++++++-
> >>  1 file changed, 85 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> index 0688a69..8514f92 100644
> >> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -206,6 +206,89 @@ static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
> >>  	return 0;
> >>  }
> >>  
> >> +static int vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
> >> +				  struct kvm_io_device *this,
> >> +				  gpa_t addr, int len, void *val)
> >> +{
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	u32 intid = (addr - iodev->base_addr) * 8;
> >> +	u32 value = 0;
> >> +	int i;
> >> +
> >> +	if (iodev->redist_vcpu)
> >> +		vcpu = iodev->redist_vcpu;
> >> +
> >> +	/* Loop over all IRQs affected by this read */
> >> +	for (i = 0; i < len * 8; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +		if (irq->pending)
> >> +			value |= (1U << i);
> >> +		spin_unlock(&irq->irq_lock);
> > 
> > here there clearly is no need to take the lock (because a bool read is
> > atomic), but that should be explained in a one-line comment.
> 
> Is that really true? Isn't it that another lock holder expects full
> control over the IRQ struct, including the freedom to change values at
> will without caring about other observers?

Consider the following three cases, assuming pending is clear in the
initial state:

Case 1:
	CPU A			CPU B
	-----			-----
	read pending
				lock irq
				set pending
				unlock irq

Case 2:
	CPU A			CPU B
	-----			-----
				lock irq
	read pending
				set pending
				unlock irq


Case 3:
	CPU A			CPU B
	-----			-----
				lock irq
				set pending
				unlock irq
	read pending


The only effect of adding a lock/unlock around the read_pending()
operation is to force case 2 to be equivalent to case 3, but case 1
could still happen, so this just boils down to observing the value
before or after the write, both of which are fine.

If there were weird side effect from reading this value, or even getting
to the struct would depend on other things CPU B could do while holding
the lock, it would be a different story, but here I'm faily certain you
don't need the lock.

> I might be too paranoid here, but I think I explicitly added the lock
> here for a reason (which I don't remember anymore, sadly).
> 

Can you can find an example where something breaks without holding the
lock here?

Thanks,
-Christoffer

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

* Re: [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  2016-04-11 12:10       ` Andre Przywara
@ 2016-04-12 13:18         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 13:18 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Mon, Apr 11, 2016 at 01:10:24PM +0100, Andre Przywara wrote:
> On 31/03/16 12:31, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:43AM +0000, Andre Przywara wrote:
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
> >>  1 file changed, 42 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> index 76657ce..cde153f 100644
> >> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> >>  	return 0;
> >>  }
> >>  
> >> +static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
> >> +				 struct kvm_io_device *this,
> >> +				 gpa_t addr, int len, void *val)
> >> +{
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	u32 intid = (addr - iodev->base_addr);
> >> +	int i;
> >> +
> >> +	if (iodev->redist_vcpu)
> >> +		vcpu = iodev->redist_vcpu;
> >> +
> >> +	for (i = 0; i < len; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		((u8 *)val)[i] = irq->targets;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
> >> +				  struct kvm_io_device *this,
> >> +				  gpa_t addr, int len, const void *val)
> >> +{
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	u32 intid = (addr - iodev->base_addr);
> >> +	int i;
> >> +
> >> +	/* GICD_ITARGETSR[0-7] are read-only */
> >> +	if (intid < VGIC_NR_PRIVATE_IRQS)
> >> +		return 0;
> >> +
> >> +	for (i = 0; i < len; i++)
> >> +		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
> >> +					    ((u8 *)val)[i]);
> >> +
> >> +	return 0;
> >> +}
> >> +
> > 
> > these functions are v2 specific but are in a generic file and are not
> > named anything specific to v2?
> 
> Well, technically the target register is still defined for the GICv3
> distributor, but just RES0 if affinity routing is enabled.

Shouldn't we support that then (or do we do this already via a call to
a RAZ handle function in the register table instead)?

> But I can of course easily add a _v2_ in here.
> 
> While I look at the function, it makes me wonder if the abstraction for
> the affinity change call is actually correct at all. In contrast to the
> other vgic_v<n>_* functions this one is about the _emulated_ VGIC model,
> not the hardware GIC version.
> Also we actually only have this one user here, the other call is about
> initializing the affinity setting, for which this function is really
> overkill.

How is it overkill?  In that it takes locks which are not necessary?

> So what about we move the content of the change_affinity function in
> here (same for the v3 case later), and tackle the init case separately
> (which is trivial)?

I don't think there's much to gain in moving the code into the function,
on the contrary, but you could move the function into this file and make
it static.

So, you're saying that the current _vX_ functions we have denote the
hardware version, not the emulated version, so that would be wrong to do
here?

In that case, I think we should just add a comment at the top of this
function saying it deals with GICv2 stuff only.  That, or forget I ever
said anything here.

Thanks,
-Christoffer

> 
> > 
> >>  struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
> >>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> >> @@ -491,7 +532,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> >>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> >> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> >> +		vgic_mmio_read_target, vgic_mmio_write_target, 8),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> >>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
> >>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> >> -- 
> >> 2.7.3
> >>
> >> --
> >> 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] 276+ messages in thread

* [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
@ 2016-04-12 13:18         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 13:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 11, 2016 at 01:10:24PM +0100, Andre Przywara wrote:
> On 31/03/16 12:31, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:43AM +0000, Andre Przywara wrote:
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
> >>  1 file changed, 42 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> index 76657ce..cde153f 100644
> >> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> >>  	return 0;
> >>  }
> >>  
> >> +static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
> >> +				 struct kvm_io_device *this,
> >> +				 gpa_t addr, int len, void *val)
> >> +{
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	u32 intid = (addr - iodev->base_addr);
> >> +	int i;
> >> +
> >> +	if (iodev->redist_vcpu)
> >> +		vcpu = iodev->redist_vcpu;
> >> +
> >> +	for (i = 0; i < len; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		((u8 *)val)[i] = irq->targets;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
> >> +				  struct kvm_io_device *this,
> >> +				  gpa_t addr, int len, const void *val)
> >> +{
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	u32 intid = (addr - iodev->base_addr);
> >> +	int i;
> >> +
> >> +	/* GICD_ITARGETSR[0-7] are read-only */
> >> +	if (intid < VGIC_NR_PRIVATE_IRQS)
> >> +		return 0;
> >> +
> >> +	for (i = 0; i < len; i++)
> >> +		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
> >> +					    ((u8 *)val)[i]);
> >> +
> >> +	return 0;
> >> +}
> >> +
> > 
> > these functions are v2 specific but are in a generic file and are not
> > named anything specific to v2?
> 
> Well, technically the target register is still defined for the GICv3
> distributor, but just RES0 if affinity routing is enabled.

Shouldn't we support that then (or do we do this already via a call to
a RAZ handle function in the register table instead)?

> But I can of course easily add a _v2_ in here.
> 
> While I look at the function, it makes me wonder if the abstraction for
> the affinity change call is actually correct at all. In contrast to the
> other vgic_v<n>_* functions this one is about the _emulated_ VGIC model,
> not the hardware GIC version.
> Also we actually only have this one user here, the other call is about
> initializing the affinity setting, for which this function is really
> overkill.

How is it overkill?  In that it takes locks which are not necessary?

> So what about we move the content of the change_affinity function in
> here (same for the v3 case later), and tackle the init case separately
> (which is trivial)?

I don't think there's much to gain in moving the code into the function,
on the contrary, but you could move the function into this file and make
it static.

So, you're saying that the current _vX_ functions we have denote the
hardware version, not the emulated version, so that would be wrong to do
here?

In that case, I think we should just add a comment at the top of this
function saying it deals with GICv2 stuff only.  That, or forget I ever
said anything here.

Thanks,
-Christoffer

> 
> > 
> >>  struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
> >>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> >> @@ -491,7 +532,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> >>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> >> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
> >> +		vgic_mmio_read_target, vgic_mmio_write_target, 8),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> >>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
> >>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> >> -- 
> >> 2.7.3
> >>
> >> --
> >> 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] 276+ messages in thread

* Re: [RFC PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
  2016-04-11 13:00       ` Andre Przywara
@ 2016-04-12 13:20         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 13:20 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Mon, Apr 11, 2016 at 02:00:02PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 31/03/16 12:53, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:47AM +0000, Andre Przywara wrote:
> >> As in the GICv2 emulation we handle those three registers in one
> >> function.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic.h      |  2 ++
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 38 ++++++++++++++++++++++++++++++++++++--
> >>  2 files changed, 38 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> >> index 4b8952a..0db1abe 100644
> >> --- a/virt/kvm/arm/vgic/vgic.h
> >> +++ b/virt/kvm/arm/vgic/vgic.h
> >> @@ -19,6 +19,8 @@
> >>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
> >>  #define IMPLEMENTER_ARM		0x43b
> >>  
> >> +#define INTERRUPT_ID_BITS_SPIS	10
> >> +
> >>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>  			      u32 intid);
> >>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> index 2d10c06..13e101f 100644
> >> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -606,7 +606,29 @@ static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
> >>  				  struct kvm_io_device *this,
> >>  				  gpa_t addr, int len, void *val)
> >>  {
> >> -	/* TODO: implement */
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	u32 value = 0;
> >> +
> >> +	switch ((addr - iodev->base_addr) & ~3) {
> >> +	case GICD_CTLR:
> >> +		if (vcpu->kvm->arch.vgic.enabled)
> >> +		       value |=	GICD_CTLR_ENABLE_SS_G1;
> >> +		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
> >> +		break;
> >> +	case GICD_TYPER:
> >> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> >> +		value = (value >> 5) - 1;
> >> +		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
> >> +		break;
> >> +	case GICD_IIDR:
> >> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> >> +		break;
> >> +	default:
> >> +		return 0;
> >> +	}
> >> +
> >> +	write_mask32(value, addr & 3, len, val);
> >>  	return 0;
> >>  }
> >>  
> >> @@ -614,7 +636,19 @@ static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
> >>  				   struct kvm_io_device *this,
> >>  				   gpa_t addr, int len, const void *val)
> >>  {
> >> -	/* TODO: implement */
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	bool enabled;
> >> +
> >> +	/* These are not the bits you are looking for ... */
> > 
> > haha, nice.  But I don't understand what this case is?
> 
> Of the 16 bytes this region covers (CTLR, TYPER, IIDR) only the first
> byte is writeable, the rest is WI.
> I am afraid I have to replace the cool quote with something more
> meaningful ...
> 

You can maintain the fun quote and supplement it with a boring
explanation.

> >> +	if (addr - iodev->base_addr > 0)
> >> +		return 0;
> >> +
> >> +	/* We only care about the enable bit, all other bits are WI. */
> >> +	enabled = *(u8*)val & GICD_CTLR_ENABLE_SS_G1;
> >> +
> >> +	vcpu->kvm->arch.vgic.enabled = enabled;
> > 
> > I think some of the comments from the v2 side apply here as well.
> 
> Agreed.
> 

Thanks,
-Christoffer

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

* [RFC PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
@ 2016-04-12 13:20         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 13:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 11, 2016 at 02:00:02PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 31/03/16 12:53, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:47AM +0000, Andre Przywara wrote:
> >> As in the GICv2 emulation we handle those three registers in one
> >> function.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic.h      |  2 ++
> >>  virt/kvm/arm/vgic/vgic_mmio.c | 38 ++++++++++++++++++++++++++++++++++++--
> >>  2 files changed, 38 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> >> index 4b8952a..0db1abe 100644
> >> --- a/virt/kvm/arm/vgic/vgic.h
> >> +++ b/virt/kvm/arm/vgic/vgic.h
> >> @@ -19,6 +19,8 @@
> >>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
> >>  #define IMPLEMENTER_ARM		0x43b
> >>  
> >> +#define INTERRUPT_ID_BITS_SPIS	10
> >> +
> >>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>  			      u32 intid);
> >>  bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq);
> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >> index 2d10c06..13e101f 100644
> >> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >> @@ -606,7 +606,29 @@ static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
> >>  				  struct kvm_io_device *this,
> >>  				  gpa_t addr, int len, void *val)
> >>  {
> >> -	/* TODO: implement */
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	u32 value = 0;
> >> +
> >> +	switch ((addr - iodev->base_addr) & ~3) {
> >> +	case GICD_CTLR:
> >> +		if (vcpu->kvm->arch.vgic.enabled)
> >> +		       value |=	GICD_CTLR_ENABLE_SS_G1;
> >> +		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
> >> +		break;
> >> +	case GICD_TYPER:
> >> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> >> +		value = (value >> 5) - 1;
> >> +		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
> >> +		break;
> >> +	case GICD_IIDR:
> >> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> >> +		break;
> >> +	default:
> >> +		return 0;
> >> +	}
> >> +
> >> +	write_mask32(value, addr & 3, len, val);
> >>  	return 0;
> >>  }
> >>  
> >> @@ -614,7 +636,19 @@ static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
> >>  				   struct kvm_io_device *this,
> >>  				   gpa_t addr, int len, const void *val)
> >>  {
> >> -	/* TODO: implement */
> >> +	struct vgic_io_device *iodev = container_of(this,
> >> +						    struct vgic_io_device, dev);
> >> +	bool enabled;
> >> +
> >> +	/* These are not the bits you are looking for ... */
> > 
> > haha, nice.  But I don't understand what this case is?
> 
> Of the 16 bytes this region covers (CTLR, TYPER, IIDR) only the first
> byte is writeable, the rest is WI.
> I am afraid I have to replace the cool quote with something more
> meaningful ...
> 

You can maintain the fun quote and supplement it with a boring
explanation.

> >> +	if (addr - iodev->base_addr > 0)
> >> +		return 0;
> >> +
> >> +	/* We only care about the enable bit, all other bits are WI. */
> >> +	enabled = *(u8*)val & GICD_CTLR_ENABLE_SS_G1;
> >> +
> >> +	vcpu->kvm->arch.vgic.enabled = enabled;
> > 
> > I think some of the comments from the v2 side apply here as well.
> 
> Agreed.
> 

Thanks,
-Christoffer

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

* Re: [RFC PATCH 45/45] KVM: arm/arm64: vgic-new: enable build
  2016-04-11 14:45       ` Andre Przywara
@ 2016-04-12 13:21         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 13:21 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Mon, Apr 11, 2016 at 03:45:02PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 31/03/16 19:18, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:05:08AM +0000, Andre Przywara wrote:
> >> Now that the new VGIC implementation has reached feature parity with
> >> the old one, add the new files to the build system and add a Kconfig
> >> option to switch between the two versions.
> >> We set the default to the new version to get maximum test coverage,
> >> in case people experience problems they can switch back to the old
> >> behaviour if needed.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  arch/arm/kvm/Kconfig    |  7 +++++++
> >>  arch/arm/kvm/Makefile   | 10 ++++++++++
> >>  arch/arm64/kvm/Kconfig  |  7 +++++++
> >>  arch/arm64/kvm/Makefile | 10 ++++++++++
> >>  4 files changed, 34 insertions(+)
> >>
> >> diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
> >> index 95a0005..02abfff 100644
> >> --- a/arch/arm/kvm/Kconfig
> >> +++ b/arch/arm/kvm/Kconfig
> >> @@ -46,6 +46,13 @@ config KVM_ARM_HOST
> >>  	---help---
> >>  	  Provides host support for ARM processors.
> >>  
> >> +config KVM_NEW_VGIC
> >> +	bool "New VGIC implementation"
> >> +	depends on KVM
> >> +	default y
> >> +	---help---
> >> +	  uses the new VGIC implementation
> >> +
> > 
> > I had imagined we'd name it in the reverse, so the option would have
> > been CONFIG_KVM_VGIC_LEGACY, but I guess the net effect should be the
> > same, assuming most people just go with the default anyway.
> 
> I think originally the assumption was to make the old VGIC the default
> in the beginning, but that changed later. By that time I considered it
> too tedious to change all patches in this regard, so I just kept the old
> symbol and semantic in.
> Shouldn't matter, really, I guess there are arguments for both ways.
> 

Agreed, shouldn't matter.

-Christoffer

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

* [RFC PATCH 45/45] KVM: arm/arm64: vgic-new: enable build
@ 2016-04-12 13:21         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 13:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 11, 2016 at 03:45:02PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 31/03/16 19:18, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:05:08AM +0000, Andre Przywara wrote:
> >> Now that the new VGIC implementation has reached feature parity with
> >> the old one, add the new files to the build system and add a Kconfig
> >> option to switch between the two versions.
> >> We set the default to the new version to get maximum test coverage,
> >> in case people experience problems they can switch back to the old
> >> behaviour if needed.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  arch/arm/kvm/Kconfig    |  7 +++++++
> >>  arch/arm/kvm/Makefile   | 10 ++++++++++
> >>  arch/arm64/kvm/Kconfig  |  7 +++++++
> >>  arch/arm64/kvm/Makefile | 10 ++++++++++
> >>  4 files changed, 34 insertions(+)
> >>
> >> diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
> >> index 95a0005..02abfff 100644
> >> --- a/arch/arm/kvm/Kconfig
> >> +++ b/arch/arm/kvm/Kconfig
> >> @@ -46,6 +46,13 @@ config KVM_ARM_HOST
> >>  	---help---
> >>  	  Provides host support for ARM processors.
> >>  
> >> +config KVM_NEW_VGIC
> >> +	bool "New VGIC implementation"
> >> +	depends on KVM
> >> +	default y
> >> +	---help---
> >> +	  uses the new VGIC implementation
> >> +
> > 
> > I had imagined we'd name it in the reverse, so the option would have
> > been CONFIG_KVM_VGIC_LEGACY, but I guess the net effect should be the
> > same, assuming most people just go with the default anyway.
> 
> I think originally the assumption was to make the old VGIC the default
> in the beginning, but that changed later. By that time I considered it
> too tedious to change all patches in this regard, so I just kept the old
> symbol and semantic in.
> Shouldn't matter, really, I guess there are arguments for both ways.
> 

Agreed, shouldn't matter.

-Christoffer

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

* Re: [RFC PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-03-30 20:40     ` Christoffer Dall
@ 2016-04-12 13:59       ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-12 13:59 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 30/03/16 21:40, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:33AM +0000, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> As the GICv3 virtual interface registers differ from their GICv2
>> siblings, we need different handlers for processing maintenance
>> interrupts and reading/writing to the LRs.
>> Also as we store an IRQ's affinity directly as a MPIDR, we need a
>> separate change_affinity() implementation too.
> 
> not sure why we embed the vgic_v3_irq_change_affinity in this patch here
> and had a stand-alone patch for v2?
> 
> I think it would be better to split them up and again have one patch to
> introduce the infrastructure for some piece of functionality, followed
> by 2 patches, one plugging in the v2 part, the other plugging in the v3
> part.

Agreed. I now have:

KVM: arm/arm64: vgic-new: Add IRQ sorting
KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq

The second patch contains the common code and some empty stub functions,
that the following two patches fill with calls to their respective
implementations. I found this nicer than the other way around.
Still not sure whether IRQ sorting or kvm_vgic_vcpu_pending_irq really
deserve a separate patch, but it makes it easier to review, I guess.

>> Implement the respective handler functions and connect them to
>> existing code to be called if the host is using a GICv3.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic-v3.c | 191 ++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c    |   8 +-
>>  virt/kvm/arm/vgic/vgic.h    |  30 +++++++
>>  3 files changed, 225 insertions(+), 4 deletions(-)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> new file mode 100644
>> index 0000000..71b4bad
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -0,0 +1,191 @@
>> +/*
>> + * 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/irqchip/arm-gic-v3.h>
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <linux/irqchip/arm-gic.h>
>> +
>> +#include "vgic.h"
>> +
>> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +
>> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
>> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, &eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
>> +			u32 intid;
>> +			u64 val = cpuif->vgic_lr[lr];
>> +
>> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
>> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
>> +			else
>> +				intid = val & GICH_LR_VIRTUALID;
>> +
>> +			/*
>> +			 * kvm_notify_acked_irq calls kvm_set_irq()
>> +			 * to reset the IRQ level, which grabs the dist->lock
>> +			 * so we call this before taking the dist->lock.
>> +			 */
> 
> this comment clearly doesn't apply anymore.
> 
> also, looking at the similarities here with the v2 code, we should
> probably have another look at sharing some more code between v2 and v3.

Admittedly the code _looks_ similar, but in fact it isn't.
The variable names are mostly the same, but many types (both the members
of struct vgic_v3_cpu_if and the actual LR register itself, for
instance) are different. Also the EISR bitmap is handled slightly
differently.
So merging this looks like it will become messy.

> 
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
>> +			cpuif->vgic_lr[lr] &= ~ICH_LR_STATE; /* Useful?? */
> 
> here you don't have the WARN that you had in v2, so does this mean we
> can actually come here with the LR state field having some value?

I don't have a real clue here, I guess the semantics are the same and
the missing WARN_ON is just an implementation detail.

>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>> +		}
>> +
>> +		/*
>> +		 * In the next iterations of the vcpu loop, if we sync
>> +		 * the vgic state after flushing it, but before
>> +		 * entering the guest (this happens for pending
>> +		 * signals and vmid rollovers), then make sure we
>> +		 * don't pick up any old maintenance interrupts here.
>> +		 */
>> +		cpuif->vgic_eisr = 0;
>> +	}
>> +
>> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
> 
> like in the v2 case, I think this should be moved out of the process
> maintenance function.

I am not sure about this one (since this function deals with exactly
this maintenance interrupt), but moved it anyway.

>> +}
>> +
>> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +
>> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
>> +}
>> +
>> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +	int lr;
>> +
>> +	/* Assumes ap_list_lock held */
>> +
>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>> +		u64 val = cpuif->vgic_lr[lr];
>> +		u32 intid;
>> +		struct vgic_irq *irq;
>> +
>> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
>> +			intid = val & ICH_LR_VIRTUAL_ID_MASK;
>> +		else
>> +			intid = val & GICH_LR_VIRTUALID;
>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/* Always preserve the active bit */
>> +		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
>> +
>> +		/* Edge is the only case where we preserve the pending bit */
>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>> +		    (val & ICH_LR_PENDING_BIT)) {
>> +			irq->pending = true;
>> +
>> +			if (intid < VGIC_NR_SGIS &&
>> +			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>> +
>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
>> +				irq->source |= (1 << cpuid);
>> +			}
>> +		}
>> +
>> +		/* Clear soft pending state when level irqs have been acked */
>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>> +		    !(val & ICH_LR_PENDING_BIT)) {
>> +			irq->soft_pending = false;
>> +			irq->pending = irq->line_level;
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +}
>> +
>> +/* Requires the irq to be locked already */
>> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>> +{
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +	u64 val;
>> +
>> +	if (!irq) {
>> +		val = 0;
>> +		goto out;
>> +	}
>> +
>> +	val = irq->intid;
>> +
>> +	if (irq->pending) {
>> +		val |= ICH_LR_PENDING_BIT;
>> +
>> +		if (irq->config == VGIC_CONFIG_EDGE)
>> +			irq->pending = false;
>> +
>> +		if (irq->intid < VGIC_NR_SGIS &&
>> +		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
>> +			u32 src = ffs(irq->source);
>> +
>> +			BUG_ON(!src);
>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>> +			irq->source &= ~(1 << (src - 1));
>> +			if (irq->source)
>> +				irq->pending = true;
>> +		}
>> +	}
>> +
>> +	if (irq->active)
>> +		val |= ICH_LR_ACTIVE_BIT;
>> +
>> +	if (irq->hw) {
>> +		val |= ICH_LR_HW;
>> +		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
>> +	} else {
>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>> +			val |= ICH_LR_EOI;
>> +	}
> 
> indeed this code looks very much like the v2 code, so maybe Marc had a
> point when he argued for this being more shared between v2 and v3.  Is
> there a nice way to do that without an intermediate LR representation?

The same arguments as above for the process_maintenance() function:
The types and bit offsets are all different. In the end the actual LR
definition is quite different between v2 and v3, so IMHO separate
functions are justified.
The similarity is the v2 multi-source SGI handling, which could be moved
into a separate function, maybe.

Anyway we should aim at streamlining both versions, though, for having
the same functionality and checks in both.

So for the next version I will keep both process_maintenance() and
populate_lr() separate. Feel free to insist on a merge or even come up
with patches afterwards ;-)

> 
>> +
>> +	/*
>> +	 * Currently all guest IRQs are Group1, as Group0 would result
>> +	 * in a FIQ in the guest, which it wouldn't expect.
>> +	 * Eventually we want to make this configurable, so we may
>> +	 * revisit this in the future.
> 
> I know we have something similar in the current code, but I actually
> don't understand this.  If the IRQ is programmed to be group0, then the
> guest *would* expect an FIQ, or?
> 
> Why is this not a matter of reading which group this IRQ is configured
> to be?

Because we don't implement IGROUPR setting atm, neither for the old nor
the new VGIC. If I now start thinking about CTLR.DS and its
implications, my brain will overrun, I am afraid.
So I'd love to move an addition of this feature to a later point in time.

Cheers,
Andre.

> 
>> +	 */
>> +	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
>> +		val |= ICH_LR_GROUP;
>> +
>> +out:
>> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
>> +}
>> +
>> +void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +	struct vgic_irq *irq;
>> +	struct kvm_vcpu *vcpu;
>> +
>> +	BUG_ON(intid <= VGIC_MAX_PRIVATE || intid > 1019);
>> +	BUG_ON(dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3);
> 
> do we need the last BUG_ON?
> 
>> +
>> +	irq = vgic_get_irq(kvm, NULL, intid);
>> +	vcpu = kvm_mpidr_to_vcpu(kvm, mpidr);
>> +
>> +	spin_lock(&irq->irq_lock);
>> +	irq->target_vcpu = vcpu;
>> +	spin_unlock(&irq->irq_lock);
>> +}
> 
> 
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 90a85bf..9eb031e8 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -368,7 +368,7 @@ static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>>  	if (kvm_vgic_global_state.type == VGIC_V2)
>>  		vgic_v2_process_maintenance(vcpu);
>>  	else
>> -		WARN(1, "GICv3 Not Implemented\n");
>> +		vgic_v3_process_maintenance(vcpu);
>>  }
>>  
>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>> @@ -376,7 +376,7 @@ static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>>  	if (kvm_vgic_global_state.type == VGIC_V2)
>>  		vgic_v2_fold_lr_state(vcpu);
>>  	else
>> -		WARN(1, "GICv3 Not Implemented\n");
>> +		vgic_v3_fold_lr_state(vcpu);
>>  }
>>  
>>  /*
>> @@ -390,7 +390,7 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>>  	if (kvm_vgic_global_state.type == VGIC_V2)
>>  		vgic_v2_populate_lr(vcpu, irq, lr);
>>  	else
>> -		WARN(1, "GICv3 Not Implemented\n");
>> +		vgic_v3_populate_lr(vcpu, irq, lr);
>>  }
>>  
>>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>> @@ -398,7 +398,7 @@ static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>>  	if (kvm_vgic_global_state.type == VGIC_V2)
>>  		vgic_v2_set_underflow(vcpu);
>>  	else
>> -		WARN(1, "GICv3 Not Implemented\n");
>> +		vgic_v3_set_underflow(vcpu);
>>  }
>>  
>>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 95ef3cf..53730ba 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -26,4 +26,34 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>>  
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
>> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
>> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
>> +#else
>> +static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
>> +					       u64 mpidr)
>> +{
>> +}
>> +
>> +static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>> +static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>> +static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
>> +				       struct vgic_irq *irq, int lr)
>> +{
>> +}
>> +
>> +static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +#endif
>> +
>>  #endif
>> -- 
>> 2.7.3
>>
> 

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

* [RFC PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-04-12 13:59       ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-12 13:59 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 30/03/16 21:40, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:33AM +0000, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> As the GICv3 virtual interface registers differ from their GICv2
>> siblings, we need different handlers for processing maintenance
>> interrupts and reading/writing to the LRs.
>> Also as we store an IRQ's affinity directly as a MPIDR, we need a
>> separate change_affinity() implementation too.
> 
> not sure why we embed the vgic_v3_irq_change_affinity in this patch here
> and had a stand-alone patch for v2?
> 
> I think it would be better to split them up and again have one patch to
> introduce the infrastructure for some piece of functionality, followed
> by 2 patches, one plugging in the v2 part, the other plugging in the v3
> part.

Agreed. I now have:

KVM: arm/arm64: vgic-new: Add IRQ sorting
KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq

The second patch contains the common code and some empty stub functions,
that the following two patches fill with calls to their respective
implementations. I found this nicer than the other way around.
Still not sure whether IRQ sorting or kvm_vgic_vcpu_pending_irq really
deserve a separate patch, but it makes it easier to review, I guess.

>> Implement the respective handler functions and connect them to
>> existing code to be called if the host is using a GICv3.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic-v3.c | 191 ++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c    |   8 +-
>>  virt/kvm/arm/vgic/vgic.h    |  30 +++++++
>>  3 files changed, 225 insertions(+), 4 deletions(-)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> new file mode 100644
>> index 0000000..71b4bad
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -0,0 +1,191 @@
>> +/*
>> + * 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/irqchip/arm-gic-v3.h>
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <linux/irqchip/arm-gic.h>
>> +
>> +#include "vgic.h"
>> +
>> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +
>> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
>> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, &eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
>> +			u32 intid;
>> +			u64 val = cpuif->vgic_lr[lr];
>> +
>> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
>> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
>> +			else
>> +				intid = val & GICH_LR_VIRTUALID;
>> +
>> +			/*
>> +			 * kvm_notify_acked_irq calls kvm_set_irq()
>> +			 * to reset the IRQ level, which grabs the dist->lock
>> +			 * so we call this before taking the dist->lock.
>> +			 */
> 
> this comment clearly doesn't apply anymore.
> 
> also, looking at the similarities here with the v2 code, we should
> probably have another look at sharing some more code between v2 and v3.

Admittedly the code _looks_ similar, but in fact it isn't.
The variable names are mostly the same, but many types (both the members
of struct vgic_v3_cpu_if and the actual LR register itself, for
instance) are different. Also the EISR bitmap is handled slightly
differently.
So merging this looks like it will become messy.

> 
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
>> +			cpuif->vgic_lr[lr] &= ~ICH_LR_STATE; /* Useful?? */
> 
> here you don't have the WARN that you had in v2, so does this mean we
> can actually come here with the LR state field having some value?

I don't have a real clue here, I guess the semantics are the same and
the missing WARN_ON is just an implementation detail.

>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>> +		}
>> +
>> +		/*
>> +		 * In the next iterations of the vcpu loop, if we sync
>> +		 * the vgic state after flushing it, but before
>> +		 * entering the guest (this happens for pending
>> +		 * signals and vmid rollovers), then make sure we
>> +		 * don't pick up any old maintenance interrupts here.
>> +		 */
>> +		cpuif->vgic_eisr = 0;
>> +	}
>> +
>> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
> 
> like in the v2 case, I think this should be moved out of the process
> maintenance function.

I am not sure about this one (since this function deals with exactly
this maintenance interrupt), but moved it anyway.

>> +}
>> +
>> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +
>> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
>> +}
>> +
>> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +	int lr;
>> +
>> +	/* Assumes ap_list_lock held */
>> +
>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>> +		u64 val = cpuif->vgic_lr[lr];
>> +		u32 intid;
>> +		struct vgic_irq *irq;
>> +
>> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
>> +			intid = val & ICH_LR_VIRTUAL_ID_MASK;
>> +		else
>> +			intid = val & GICH_LR_VIRTUALID;
>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/* Always preserve the active bit */
>> +		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
>> +
>> +		/* Edge is the only case where we preserve the pending bit */
>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>> +		    (val & ICH_LR_PENDING_BIT)) {
>> +			irq->pending = true;
>> +
>> +			if (intid < VGIC_NR_SGIS &&
>> +			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>> +
>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
>> +				irq->source |= (1 << cpuid);
>> +			}
>> +		}
>> +
>> +		/* Clear soft pending state when level irqs have been acked */
>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>> +		    !(val & ICH_LR_PENDING_BIT)) {
>> +			irq->soft_pending = false;
>> +			irq->pending = irq->line_level;
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +}
>> +
>> +/* Requires the irq to be locked already */
>> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>> +{
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +	u64 val;
>> +
>> +	if (!irq) {
>> +		val = 0;
>> +		goto out;
>> +	}
>> +
>> +	val = irq->intid;
>> +
>> +	if (irq->pending) {
>> +		val |= ICH_LR_PENDING_BIT;
>> +
>> +		if (irq->config == VGIC_CONFIG_EDGE)
>> +			irq->pending = false;
>> +
>> +		if (irq->intid < VGIC_NR_SGIS &&
>> +		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
>> +			u32 src = ffs(irq->source);
>> +
>> +			BUG_ON(!src);
>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>> +			irq->source &= ~(1 << (src - 1));
>> +			if (irq->source)
>> +				irq->pending = true;
>> +		}
>> +	}
>> +
>> +	if (irq->active)
>> +		val |= ICH_LR_ACTIVE_BIT;
>> +
>> +	if (irq->hw) {
>> +		val |= ICH_LR_HW;
>> +		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
>> +	} else {
>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>> +			val |= ICH_LR_EOI;
>> +	}
> 
> indeed this code looks very much like the v2 code, so maybe Marc had a
> point when he argued for this being more shared between v2 and v3.  Is
> there a nice way to do that without an intermediate LR representation?

The same arguments as above for the process_maintenance() function:
The types and bit offsets are all different. In the end the actual LR
definition is quite different between v2 and v3, so IMHO separate
functions are justified.
The similarity is the v2 multi-source SGI handling, which could be moved
into a separate function, maybe.

Anyway we should aim at streamlining both versions, though, for having
the same functionality and checks in both.

So for the next version I will keep both process_maintenance() and
populate_lr() separate. Feel free to insist on a merge or even come up
with patches afterwards ;-)

> 
>> +
>> +	/*
>> +	 * Currently all guest IRQs are Group1, as Group0 would result
>> +	 * in a FIQ in the guest, which it wouldn't expect.
>> +	 * Eventually we want to make this configurable, so we may
>> +	 * revisit this in the future.
> 
> I know we have something similar in the current code, but I actually
> don't understand this.  If the IRQ is programmed to be group0, then the
> guest *would* expect an FIQ, or?
> 
> Why is this not a matter of reading which group this IRQ is configured
> to be?

Because we don't implement IGROUPR setting atm, neither for the old nor
the new VGIC. If I now start thinking about CTLR.DS and its
implications, my brain will overrun, I am afraid.
So I'd love to move an addition of this feature to a later point in time.

Cheers,
Andre.

> 
>> +	 */
>> +	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
>> +		val |= ICH_LR_GROUP;
>> +
>> +out:
>> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
>> +}
>> +
>> +void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr)
>> +{
>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>> +	struct vgic_irq *irq;
>> +	struct kvm_vcpu *vcpu;
>> +
>> +	BUG_ON(intid <= VGIC_MAX_PRIVATE || intid > 1019);
>> +	BUG_ON(dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3);
> 
> do we need the last BUG_ON?
> 
>> +
>> +	irq = vgic_get_irq(kvm, NULL, intid);
>> +	vcpu = kvm_mpidr_to_vcpu(kvm, mpidr);
>> +
>> +	spin_lock(&irq->irq_lock);
>> +	irq->target_vcpu = vcpu;
>> +	spin_unlock(&irq->irq_lock);
>> +}
> 
> 
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 90a85bf..9eb031e8 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -368,7 +368,7 @@ static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>>  	if (kvm_vgic_global_state.type == VGIC_V2)
>>  		vgic_v2_process_maintenance(vcpu);
>>  	else
>> -		WARN(1, "GICv3 Not Implemented\n");
>> +		vgic_v3_process_maintenance(vcpu);
>>  }
>>  
>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>> @@ -376,7 +376,7 @@ static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>>  	if (kvm_vgic_global_state.type == VGIC_V2)
>>  		vgic_v2_fold_lr_state(vcpu);
>>  	else
>> -		WARN(1, "GICv3 Not Implemented\n");
>> +		vgic_v3_fold_lr_state(vcpu);
>>  }
>>  
>>  /*
>> @@ -390,7 +390,7 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>>  	if (kvm_vgic_global_state.type == VGIC_V2)
>>  		vgic_v2_populate_lr(vcpu, irq, lr);
>>  	else
>> -		WARN(1, "GICv3 Not Implemented\n");
>> +		vgic_v3_populate_lr(vcpu, irq, lr);
>>  }
>>  
>>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>> @@ -398,7 +398,7 @@ static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>>  	if (kvm_vgic_global_state.type == VGIC_V2)
>>  		vgic_v2_set_underflow(vcpu);
>>  	else
>> -		WARN(1, "GICv3 Not Implemented\n");
>> +		vgic_v3_set_underflow(vcpu);
>>  }
>>  
>>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 95ef3cf..53730ba 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -26,4 +26,34 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>>  
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, u64 mpidr);
>> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
>> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
>> +#else
>> +static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid,
>> +					       u64 mpidr)
>> +{
>> +}
>> +
>> +static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>> +static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>> +static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
>> +				       struct vgic_irq *irq, int lr)
>> +{
>> +}
>> +
>> +static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +#endif
>> +
>>  #endif
>> -- 
>> 2.7.3
>>
> 

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

* Re: [RFC PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-04-12 13:59       ` Andre Przywara
@ 2016-04-12 15:02         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 15:02 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Tue, Apr 12, 2016 at 02:59:04PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 30/03/16 21:40, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:33AM +0000, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> As the GICv3 virtual interface registers differ from their GICv2
> >> siblings, we need different handlers for processing maintenance
> >> interrupts and reading/writing to the LRs.
> >> Also as we store an IRQ's affinity directly as a MPIDR, we need a
> >> separate change_affinity() implementation too.
> > 
> > not sure why we embed the vgic_v3_irq_change_affinity in this patch here
> > and had a stand-alone patch for v2?
> > 
> > I think it would be better to split them up and again have one patch to
> > introduce the infrastructure for some piece of functionality, followed
> > by 2 patches, one plugging in the v2 part, the other plugging in the v3
> > part.
> 
> Agreed. I now have:
> 
> KVM: arm/arm64: vgic-new: Add IRQ sorting
> KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
> KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
> KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
> KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
> 
> The second patch contains the common code and some empty stub functions,
> that the following two patches fill with calls to their respective
> implementations. I found this nicer than the other way around.
> Still not sure whether IRQ sorting or kvm_vgic_vcpu_pending_irq really
> deserve a separate patch, but it makes it easier to review, I guess.
> 
> >> Implement the respective handler functions and connect them to
> >> existing code to be called if the host is using a GICv3.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic-v3.c | 191 ++++++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.c    |   8 +-
> >>  virt/kvm/arm/vgic/vgic.h    |  30 +++++++
> >>  3 files changed, 225 insertions(+), 4 deletions(-)
> >>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> >> new file mode 100644
> >> index 0000000..71b4bad
> >> --- /dev/null
> >> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> >> @@ -0,0 +1,191 @@
> >> +/*
> >> + * 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/irqchip/arm-gic-v3.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_host.h>
> >> +#include <linux/irqchip/arm-gic.h>
> >> +
> >> +#include "vgic.h"
> >> +
> >> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> >> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> >> +
> >> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
> >> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
> >> +		int lr;
> >> +
> >> +		for_each_set_bit(lr, &eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> >> +			u32 intid;
> >> +			u64 val = cpuif->vgic_lr[lr];
> >> +
> >> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> >> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
> >> +			else
> >> +				intid = val & GICH_LR_VIRTUALID;
> >> +
> >> +			/*
> >> +			 * kvm_notify_acked_irq calls kvm_set_irq()
> >> +			 * to reset the IRQ level, which grabs the dist->lock
> >> +			 * so we call this before taking the dist->lock.
> >> +			 */
> > 
> > this comment clearly doesn't apply anymore.
> > 
> > also, looking at the similarities here with the v2 code, we should
> > probably have another look at sharing some more code between v2 and v3.
> 
> Admittedly the code _looks_ similar, but in fact it isn't.
> The variable names are mostly the same, but many types (both the members
> of struct vgic_v3_cpu_if and the actual LR register itself, for
> instance) are different. Also the EISR bitmap is handled slightly
> differently.
> So merging this looks like it will become messy.
> 
> > 
> >> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >> +
> >> +			cpuif->vgic_lr[lr] &= ~ICH_LR_STATE; /* Useful?? */
> > 
> > here you don't have the WARN that you had in v2, so does this mean we
> > can actually come here with the LR state field having some value?
> 
> I don't have a real clue here, I guess the semantics are the same and
> the missing WARN_ON is just an implementation detail.
> 

I think the two implementations should be similar in that sense.
Differences like this in sych symmetric code tend to be confusing later
on.

> >> +			cpuif->vgic_elrsr |= 1ULL << lr;
> >> +		}
> >> +
> >> +		/*
> >> +		 * In the next iterations of the vcpu loop, if we sync
> >> +		 * the vgic state after flushing it, but before
> >> +		 * entering the guest (this happens for pending
> >> +		 * signals and vmid rollovers), then make sure we
> >> +		 * don't pick up any old maintenance interrupts here.
> >> +		 */
> >> +		cpuif->vgic_eisr = 0;
> >> +	}
> >> +
> >> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
> > 
> > like in the v2 case, I think this should be moved out of the process
> > maintenance function.
> 
> I am not sure about this one (since this function deals with exactly
> this maintenance interrupt), but moved it anyway.
> 

ah, I was thinking of this function as dealing with EOI interrupts only,
but you're right.  The confusing part though is that this bit is cleared
regardless of whether or not there was a maintenance interrupt.

So, it's up to you.


> >> +}
> >> +
> >> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> >> +
> >> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
> >> +}
> >> +
> >> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> >> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> >> +	int lr;
> >> +
> >> +	/* Assumes ap_list_lock held */
> >> +
> >> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> >> +		u64 val = cpuif->vgic_lr[lr];
> >> +		u32 intid;
> >> +		struct vgic_irq *irq;
> >> +
> >> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> >> +			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> >> +		else
> >> +			intid = val & GICH_LR_VIRTUALID;
> >> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/* Always preserve the active bit */
> >> +		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
> >> +
> >> +		/* Edge is the only case where we preserve the pending bit */
> >> +		if (irq->config == VGIC_CONFIG_EDGE &&
> >> +		    (val & ICH_LR_PENDING_BIT)) {
> >> +			irq->pending = true;
> >> +
> >> +			if (intid < VGIC_NR_SGIS &&
> >> +			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> >> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> >> +
> >> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> >> +				irq->source |= (1 << cpuid);
> >> +			}
> >> +		}
> >> +
> >> +		/* Clear soft pending state when level irqs have been acked */
> >> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> >> +		    !(val & ICH_LR_PENDING_BIT)) {
> >> +			irq->soft_pending = false;
> >> +			irq->pending = irq->line_level;
> >> +		}
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +	}
> >> +}
> >> +
> >> +/* Requires the irq to be locked already */
> >> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> >> +{
> >> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> >> +	u64 val;
> >> +
> >> +	if (!irq) {
> >> +		val = 0;
> >> +		goto out;
> >> +	}
> >> +
> >> +	val = irq->intid;
> >> +
> >> +	if (irq->pending) {
> >> +		val |= ICH_LR_PENDING_BIT;
> >> +
> >> +		if (irq->config == VGIC_CONFIG_EDGE)
> >> +			irq->pending = false;
> >> +
> >> +		if (irq->intid < VGIC_NR_SGIS &&
> >> +		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> >> +			u32 src = ffs(irq->source);
> >> +
> >> +			BUG_ON(!src);
> >> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> >> +			irq->source &= ~(1 << (src - 1));
> >> +			if (irq->source)
> >> +				irq->pending = true;
> >> +		}
> >> +	}
> >> +
> >> +	if (irq->active)
> >> +		val |= ICH_LR_ACTIVE_BIT;
> >> +
> >> +	if (irq->hw) {
> >> +		val |= ICH_LR_HW;
> >> +		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
> >> +	} else {
> >> +		if (irq->config == VGIC_CONFIG_LEVEL)
> >> +			val |= ICH_LR_EOI;
> >> +	}
> > 
> > indeed this code looks very much like the v2 code, so maybe Marc had a
> > point when he argued for this being more shared between v2 and v3.  Is
> > there a nice way to do that without an intermediate LR representation?
> 
> The same arguments as above for the process_maintenance() function:
> The types and bit offsets are all different. In the end the actual LR
> definition is quite different between v2 and v3, so IMHO separate
> functions are justified.
> The similarity is the v2 multi-source SGI handling, which could be moved
> into a separate function, maybe.
> 
> Anyway we should aim at streamlining both versions, though, for having
> the same functionality and checks in both.
> 
> So for the next version I will keep both process_maintenance() and
> populate_lr() separate. Feel free to insist on a merge or even come up
> with patches afterwards ;-)
> 

That's fine.  You're probably a better judge of this having fiddled
around with the code so much.  If it feels cleaner to you to keep them
separate for now, let's do that, and we can play with a cleanup later if
we feel like it.

> > 
> >> +
> >> +	/*
> >> +	 * Currently all guest IRQs are Group1, as Group0 would result
> >> +	 * in a FIQ in the guest, which it wouldn't expect.
> >> +	 * Eventually we want to make this configurable, so we may
> >> +	 * revisit this in the future.
> > 
> > I know we have something similar in the current code, but I actually
> > don't understand this.  If the IRQ is programmed to be group0, then the
> > guest *would* expect an FIQ, or?
> > 
> > Why is this not a matter of reading which group this IRQ is configured
> > to be?
> 
> Because we don't implement IGROUPR setting atm, neither for the old nor
> the new VGIC. If I now start thinking about CTLR.DS and its
> implications, my brain will overrun, I am afraid.
> So I'd love to move an addition of this feature to a later point in time.
> 

That's fine, but can we tweak the comment then, because I still don't
understand the bit about what the guest expects vs. IRQs and FIQs.

If the guest programs an interrupt to Group0, wouldn't it expect to see
an FIQ, but even in this case we inject it as IRQs?  Maybe there's some
complexity here that I don't see.

I would phrase it something like:

/*
 * We don't support grouping yet and therefore hard code all interrupts
 * to be Group1 interrupts and signal IRQs (not FIQs) to the guest.
 */

But as I said, maybe I'm not getting it.

-Christoffer

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

* [RFC PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-04-12 15:02         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 15:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 12, 2016 at 02:59:04PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 30/03/16 21:40, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:33AM +0000, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> As the GICv3 virtual interface registers differ from their GICv2
> >> siblings, we need different handlers for processing maintenance
> >> interrupts and reading/writing to the LRs.
> >> Also as we store an IRQ's affinity directly as a MPIDR, we need a
> >> separate change_affinity() implementation too.
> > 
> > not sure why we embed the vgic_v3_irq_change_affinity in this patch here
> > and had a stand-alone patch for v2?
> > 
> > I think it would be better to split them up and again have one patch to
> > introduce the infrastructure for some piece of functionality, followed
> > by 2 patches, one plugging in the v2 part, the other plugging in the v3
> > part.
> 
> Agreed. I now have:
> 
> KVM: arm/arm64: vgic-new: Add IRQ sorting
> KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
> KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
> KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
> KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
> 
> The second patch contains the common code and some empty stub functions,
> that the following two patches fill with calls to their respective
> implementations. I found this nicer than the other way around.
> Still not sure whether IRQ sorting or kvm_vgic_vcpu_pending_irq really
> deserve a separate patch, but it makes it easier to review, I guess.
> 
> >> Implement the respective handler functions and connect them to
> >> existing code to be called if the host is using a GICv3.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic-v3.c | 191 ++++++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.c    |   8 +-
> >>  virt/kvm/arm/vgic/vgic.h    |  30 +++++++
> >>  3 files changed, 225 insertions(+), 4 deletions(-)
> >>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> >> new file mode 100644
> >> index 0000000..71b4bad
> >> --- /dev/null
> >> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> >> @@ -0,0 +1,191 @@
> >> +/*
> >> + * 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/irqchip/arm-gic-v3.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_host.h>
> >> +#include <linux/irqchip/arm-gic.h>
> >> +
> >> +#include "vgic.h"
> >> +
> >> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> >> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> >> +
> >> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
> >> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
> >> +		int lr;
> >> +
> >> +		for_each_set_bit(lr, &eisr_bmap, vcpu->arch.vgic_cpu.nr_lr) {
> >> +			u32 intid;
> >> +			u64 val = cpuif->vgic_lr[lr];
> >> +
> >> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> >> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
> >> +			else
> >> +				intid = val & GICH_LR_VIRTUALID;
> >> +
> >> +			/*
> >> +			 * kvm_notify_acked_irq calls kvm_set_irq()
> >> +			 * to reset the IRQ level, which grabs the dist->lock
> >> +			 * so we call this before taking the dist->lock.
> >> +			 */
> > 
> > this comment clearly doesn't apply anymore.
> > 
> > also, looking at the similarities here with the v2 code, we should
> > probably have another look at sharing some more code between v2 and v3.
> 
> Admittedly the code _looks_ similar, but in fact it isn't.
> The variable names are mostly the same, but many types (both the members
> of struct vgic_v3_cpu_if and the actual LR register itself, for
> instance) are different. Also the EISR bitmap is handled slightly
> differently.
> So merging this looks like it will become messy.
> 
> > 
> >> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >> +
> >> +			cpuif->vgic_lr[lr] &= ~ICH_LR_STATE; /* Useful?? */
> > 
> > here you don't have the WARN that you had in v2, so does this mean we
> > can actually come here with the LR state field having some value?
> 
> I don't have a real clue here, I guess the semantics are the same and
> the missing WARN_ON is just an implementation detail.
> 

I think the two implementations should be similar in that sense.
Differences like this in sych symmetric code tend to be confusing later
on.

> >> +			cpuif->vgic_elrsr |= 1ULL << lr;
> >> +		}
> >> +
> >> +		/*
> >> +		 * In the next iterations of the vcpu loop, if we sync
> >> +		 * the vgic state after flushing it, but before
> >> +		 * entering the guest (this happens for pending
> >> +		 * signals and vmid rollovers), then make sure we
> >> +		 * don't pick up any old maintenance interrupts here.
> >> +		 */
> >> +		cpuif->vgic_eisr = 0;
> >> +	}
> >> +
> >> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
> > 
> > like in the v2 case, I think this should be moved out of the process
> > maintenance function.
> 
> I am not sure about this one (since this function deals with exactly
> this maintenance interrupt), but moved it anyway.
> 

ah, I was thinking of this function as dealing with EOI interrupts only,
but you're right.  The confusing part though is that this bit is cleared
regardless of whether or not there was a maintenance interrupt.

So, it's up to you.


> >> +}
> >> +
> >> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> >> +
> >> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
> >> +}
> >> +
> >> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> >> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> >> +	int lr;
> >> +
> >> +	/* Assumes ap_list_lock held */
> >> +
> >> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> >> +		u64 val = cpuif->vgic_lr[lr];
> >> +		u32 intid;
> >> +		struct vgic_irq *irq;
> >> +
> >> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> >> +			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> >> +		else
> >> +			intid = val & GICH_LR_VIRTUALID;
> >> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/* Always preserve the active bit */
> >> +		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
> >> +
> >> +		/* Edge is the only case where we preserve the pending bit */
> >> +		if (irq->config == VGIC_CONFIG_EDGE &&
> >> +		    (val & ICH_LR_PENDING_BIT)) {
> >> +			irq->pending = true;
> >> +
> >> +			if (intid < VGIC_NR_SGIS &&
> >> +			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> >> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> >> +
> >> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> >> +				irq->source |= (1 << cpuid);
> >> +			}
> >> +		}
> >> +
> >> +		/* Clear soft pending state when level irqs have been acked */
> >> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> >> +		    !(val & ICH_LR_PENDING_BIT)) {
> >> +			irq->soft_pending = false;
> >> +			irq->pending = irq->line_level;
> >> +		}
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +	}
> >> +}
> >> +
> >> +/* Requires the irq to be locked already */
> >> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> >> +{
> >> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> >> +	u64 val;
> >> +
> >> +	if (!irq) {
> >> +		val = 0;
> >> +		goto out;
> >> +	}
> >> +
> >> +	val = irq->intid;
> >> +
> >> +	if (irq->pending) {
> >> +		val |= ICH_LR_PENDING_BIT;
> >> +
> >> +		if (irq->config == VGIC_CONFIG_EDGE)
> >> +			irq->pending = false;
> >> +
> >> +		if (irq->intid < VGIC_NR_SGIS &&
> >> +		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> >> +			u32 src = ffs(irq->source);
> >> +
> >> +			BUG_ON(!src);
> >> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> >> +			irq->source &= ~(1 << (src - 1));
> >> +			if (irq->source)
> >> +				irq->pending = true;
> >> +		}
> >> +	}
> >> +
> >> +	if (irq->active)
> >> +		val |= ICH_LR_ACTIVE_BIT;
> >> +
> >> +	if (irq->hw) {
> >> +		val |= ICH_LR_HW;
> >> +		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
> >> +	} else {
> >> +		if (irq->config == VGIC_CONFIG_LEVEL)
> >> +			val |= ICH_LR_EOI;
> >> +	}
> > 
> > indeed this code looks very much like the v2 code, so maybe Marc had a
> > point when he argued for this being more shared between v2 and v3.  Is
> > there a nice way to do that without an intermediate LR representation?
> 
> The same arguments as above for the process_maintenance() function:
> The types and bit offsets are all different. In the end the actual LR
> definition is quite different between v2 and v3, so IMHO separate
> functions are justified.
> The similarity is the v2 multi-source SGI handling, which could be moved
> into a separate function, maybe.
> 
> Anyway we should aim at streamlining both versions, though, for having
> the same functionality and checks in both.
> 
> So for the next version I will keep both process_maintenance() and
> populate_lr() separate. Feel free to insist on a merge or even come up
> with patches afterwards ;-)
> 

That's fine.  You're probably a better judge of this having fiddled
around with the code so much.  If it feels cleaner to you to keep them
separate for now, let's do that, and we can play with a cleanup later if
we feel like it.

> > 
> >> +
> >> +	/*
> >> +	 * Currently all guest IRQs are Group1, as Group0 would result
> >> +	 * in a FIQ in the guest, which it wouldn't expect.
> >> +	 * Eventually we want to make this configurable, so we may
> >> +	 * revisit this in the future.
> > 
> > I know we have something similar in the current code, but I actually
> > don't understand this.  If the IRQ is programmed to be group0, then the
> > guest *would* expect an FIQ, or?
> > 
> > Why is this not a matter of reading which group this IRQ is configured
> > to be?
> 
> Because we don't implement IGROUPR setting atm, neither for the old nor
> the new VGIC. If I now start thinking about CTLR.DS and its
> implications, my brain will overrun, I am afraid.
> So I'd love to move an addition of this feature to a later point in time.
> 

That's fine, but can we tweak the comment then, because I still don't
understand the bit about what the guest expects vs. IRQs and FIQs.

If the guest programs an interrupt to Group0, wouldn't it expect to see
an FIQ, but even in this case we inject it as IRQs?  Maybe there's some
complexity here that I don't see.

I would phrase it something like:

/*
 * We don't support grouping yet and therefore hard code all interrupts
 * to be Group1 interrupts and signal IRQs (not FIQs) to the guest.
 */

But as I said, maybe I'm not getting it.

-Christoffer

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

* Re: [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  2016-04-12 13:18         ` Christoffer Dall
@ 2016-04-12 15:18           ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-12 15:18 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm, Eric Auger

Hi,

On 12/04/16 14:18, Christoffer Dall wrote:
> On Mon, Apr 11, 2016 at 01:10:24PM +0100, Andre Przywara wrote:
>> On 31/03/16 12:31, Christoffer Dall wrote:
>>> On Fri, Mar 25, 2016 at 02:04:43AM +0000, Andre Przywara wrote:
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>>  virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
>>>>  1 file changed, 42 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>>>> index 76657ce..cde153f 100644
>>>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>>>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>>>> @@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>>>  	return 0;
>>>>  }
>>>>  
>>>> +static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
>>>> +				 struct kvm_io_device *this,
>>>> +				 gpa_t addr, int len, void *val)
>>>> +{
>>>> +	struct vgic_io_device *iodev = container_of(this,
>>>> +						    struct vgic_io_device, dev);
>>>> +	u32 intid = (addr - iodev->base_addr);
>>>> +	int i;
>>>> +
>>>> +	if (iodev->redist_vcpu)
>>>> +		vcpu = iodev->redist_vcpu;
>>>> +
>>>> +	for (i = 0; i < len; i++) {
>>>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>>> +
>>>> +		((u8 *)val)[i] = irq->targets;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
>>>> +				  struct kvm_io_device *this,
>>>> +				  gpa_t addr, int len, const void *val)
>>>> +{
>>>> +	struct vgic_io_device *iodev = container_of(this,
>>>> +						    struct vgic_io_device, dev);
>>>> +	u32 intid = (addr - iodev->base_addr);
>>>> +	int i;
>>>> +
>>>> +	/* GICD_ITARGETSR[0-7] are read-only */
>>>> +	if (intid < VGIC_NR_PRIVATE_IRQS)
>>>> +		return 0;
>>>> +
>>>> +	for (i = 0; i < len; i++)
>>>> +		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
>>>> +					    ((u8 *)val)[i]);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>
>>> these functions are v2 specific but are in a generic file and are not
>>> named anything specific to v2?
>>
>> Well, technically the target register is still defined for the GICv3
>> distributor, but just RES0 if affinity routing is enabled.
> 
> Shouldn't we support that then (or do we do this already via a call to
> a RAZ handle function in the register table instead)?

Yes:
	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),

> 
>> But I can of course easily add a _v2_ in here.
>>
>> While I look at the function, it makes me wonder if the abstraction for
>> the affinity change call is actually correct at all. In contrast to the
>> other vgic_v<n>_* functions this one is about the _emulated_ VGIC model,
>> not the hardware GIC version.
>> Also we actually only have this one user here, the other call is about
>> initializing the affinity setting, for which this function is really
>> overkill.
> 
> How is it overkill?  In that it takes locks which are not necessary?

Well, yes, and the diff for the init part looks like:
(pls excuse my stupid mailer for breaking the lines)

@@ -154,6 +154,7 @@ out:
int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
{
 	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
 	int i;

 	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
@@ -174,10 +175,11 @@ int kvm_vgic_dist_init(struct kvm *kvm, unsigned
int nr_spis)
 		INIT_LIST_HEAD(&irq->ap_list);
 		spin_lock_init(&irq->irq_lock);
 		irq->vcpu = NULL;
+		irq->target_vcpu = vcpu0;
 		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
-			vgic_v2_irq_change_affinity(kvm, irq->intid, 0);
+			irq->targets = 0;
 		else
-			vgic_v3_irq_change_affinity(kvm, irq->intid, 0);
+			irq->mpidr = 0;
 	}
 	return 0;
 }

The amended MMIO handling part for the v3 IROUTER register looks similar
(call to the function replaced with lock; assignment; unlock;). Also the
v2 implementation is still shorter than the original function.
So I am tempted to keep the change I just did in the next version.

>> So what about we move the content of the change_affinity function in
>> here (same for the v3 case later), and tackle the init case separately
>> (which is trivial)?
> 
> I don't think there's much to gain in moving the code into the function,
> on the contrary, but you could move the function into this file and make
> it static.
> 
> So, you're saying that the current _vX_ functions we have denote the
> hardware version, not the emulated version, so that would be wrong to do
> here?

Yes, at least for everything in vgic/vgic-v[23].c. So having
vgic_v2_irq_change_affinity() in there is not right.

Cheers,
Andre.

> In that case, I think we should just add a comment at the top of this
> function saying it deals with GICv2 stuff only.  That, or forget I ever
> said anything here.
> 
> Thanks,
> -Christoffer
> 
>>
>>>
>>>>  struct vgic_register_region vgic_v2_dist_registers[] = {
>>>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>>>>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>>>> @@ -491,7 +532,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>>>>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>>>> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>>>> +		vgic_mmio_read_target, vgic_mmio_write_target, 8),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>>>>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>>>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>>>> -- 
>>>> 2.7.3
>>>>
>>>> --
>>>> 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] 276+ messages in thread

* [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
@ 2016-04-12 15:18           ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-12 15:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/04/16 14:18, Christoffer Dall wrote:
> On Mon, Apr 11, 2016 at 01:10:24PM +0100, Andre Przywara wrote:
>> On 31/03/16 12:31, Christoffer Dall wrote:
>>> On Fri, Mar 25, 2016 at 02:04:43AM +0000, Andre Przywara wrote:
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>>  virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
>>>>  1 file changed, 42 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>>>> index 76657ce..cde153f 100644
>>>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>>>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>>>> @@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>>>  	return 0;
>>>>  }
>>>>  
>>>> +static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
>>>> +				 struct kvm_io_device *this,
>>>> +				 gpa_t addr, int len, void *val)
>>>> +{
>>>> +	struct vgic_io_device *iodev = container_of(this,
>>>> +						    struct vgic_io_device, dev);
>>>> +	u32 intid = (addr - iodev->base_addr);
>>>> +	int i;
>>>> +
>>>> +	if (iodev->redist_vcpu)
>>>> +		vcpu = iodev->redist_vcpu;
>>>> +
>>>> +	for (i = 0; i < len; i++) {
>>>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>>> +
>>>> +		((u8 *)val)[i] = irq->targets;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
>>>> +				  struct kvm_io_device *this,
>>>> +				  gpa_t addr, int len, const void *val)
>>>> +{
>>>> +	struct vgic_io_device *iodev = container_of(this,
>>>> +						    struct vgic_io_device, dev);
>>>> +	u32 intid = (addr - iodev->base_addr);
>>>> +	int i;
>>>> +
>>>> +	/* GICD_ITARGETSR[0-7] are read-only */
>>>> +	if (intid < VGIC_NR_PRIVATE_IRQS)
>>>> +		return 0;
>>>> +
>>>> +	for (i = 0; i < len; i++)
>>>> +		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
>>>> +					    ((u8 *)val)[i]);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>
>>> these functions are v2 specific but are in a generic file and are not
>>> named anything specific to v2?
>>
>> Well, technically the target register is still defined for the GICv3
>> distributor, but just RES0 if affinity routing is enabled.
> 
> Shouldn't we support that then (or do we do this already via a call to
> a RAZ handle function in the register table instead)?

Yes:
	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),

> 
>> But I can of course easily add a _v2_ in here.
>>
>> While I look at the function, it makes me wonder if the abstraction for
>> the affinity change call is actually correct at all. In contrast to the
>> other vgic_v<n>_* functions this one is about the _emulated_ VGIC model,
>> not the hardware GIC version.
>> Also we actually only have this one user here, the other call is about
>> initializing the affinity setting, for which this function is really
>> overkill.
> 
> How is it overkill?  In that it takes locks which are not necessary?

Well, yes, and the diff for the init part looks like:
(pls excuse my stupid mailer for breaking the lines)

@@ -154,6 +154,7 @@ out:
int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
{
 	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
 	int i;

 	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
@@ -174,10 +175,11 @@ int kvm_vgic_dist_init(struct kvm *kvm, unsigned
int nr_spis)
 		INIT_LIST_HEAD(&irq->ap_list);
 		spin_lock_init(&irq->irq_lock);
 		irq->vcpu = NULL;
+		irq->target_vcpu = vcpu0;
 		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
-			vgic_v2_irq_change_affinity(kvm, irq->intid, 0);
+			irq->targets = 0;
 		else
-			vgic_v3_irq_change_affinity(kvm, irq->intid, 0);
+			irq->mpidr = 0;
 	}
 	return 0;
 }

The amended MMIO handling part for the v3 IROUTER register looks similar
(call to the function replaced with lock; assignment; unlock;). Also the
v2 implementation is still shorter than the original function.
So I am tempted to keep the change I just did in the next version.

>> So what about we move the content of the change_affinity function in
>> here (same for the v3 case later), and tackle the init case separately
>> (which is trivial)?
> 
> I don't think there's much to gain in moving the code into the function,
> on the contrary, but you could move the function into this file and make
> it static.
> 
> So, you're saying that the current _vX_ functions we have denote the
> hardware version, not the emulated version, so that would be wrong to do
> here?

Yes, at least for everything in vgic/vgic-v[23].c. So having
vgic_v2_irq_change_affinity() in there is not right.

Cheers,
Andre.

> In that case, I think we should just add a comment at the top of this
> function saying it deals with GICv2 stuff only.  That, or forget I ever
> said anything here.
> 
> Thanks,
> -Christoffer
> 
>>
>>>
>>>>  struct vgic_register_region vgic_v2_dist_registers[] = {
>>>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>>>>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>>>> @@ -491,7 +532,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>>>>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>>>> -		vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
>>>> +		vgic_mmio_read_target, vgic_mmio_write_target, 8),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>>>>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>>>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>>>> -- 
>>>> 2.7.3
>>>>
>>>> --
>>>> 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] 276+ messages in thread

* Re: [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  2016-04-12 15:18           ` Andre Przywara
@ 2016-04-12 15:26             ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 15:26 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Tue, Apr 12, 2016 at 04:18:49PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 12/04/16 14:18, Christoffer Dall wrote:
> > On Mon, Apr 11, 2016 at 01:10:24PM +0100, Andre Przywara wrote:
> >> On 31/03/16 12:31, Christoffer Dall wrote:
> >>> On Fri, Mar 25, 2016 at 02:04:43AM +0000, Andre Przywara wrote:
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> ---
> >>>>  virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
> >>>>  1 file changed, 42 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >>>> index 76657ce..cde153f 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >>>> @@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> >>>>  	return 0;
> >>>>  }
> >>>>  
> >>>> +static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
> >>>> +				 struct kvm_io_device *this,
> >>>> +				 gpa_t addr, int len, void *val)
> >>>> +{
> >>>> +	struct vgic_io_device *iodev = container_of(this,
> >>>> +						    struct vgic_io_device, dev);
> >>>> +	u32 intid = (addr - iodev->base_addr);
> >>>> +	int i;
> >>>> +
> >>>> +	if (iodev->redist_vcpu)
> >>>> +		vcpu = iodev->redist_vcpu;
> >>>> +
> >>>> +	for (i = 0; i < len; i++) {
> >>>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >>>> +
> >>>> +		((u8 *)val)[i] = irq->targets;
> >>>> +	}
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> >>>> +static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
> >>>> +				  struct kvm_io_device *this,
> >>>> +				  gpa_t addr, int len, const void *val)
> >>>> +{
> >>>> +	struct vgic_io_device *iodev = container_of(this,
> >>>> +						    struct vgic_io_device, dev);
> >>>> +	u32 intid = (addr - iodev->base_addr);
> >>>> +	int i;
> >>>> +
> >>>> +	/* GICD_ITARGETSR[0-7] are read-only */
> >>>> +	if (intid < VGIC_NR_PRIVATE_IRQS)
> >>>> +		return 0;
> >>>> +
> >>>> +	for (i = 0; i < len; i++)
> >>>> +		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
> >>>> +					    ((u8 *)val)[i]);
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> >>>
> >>> these functions are v2 specific but are in a generic file and are not
> >>> named anything specific to v2?
> >>
> >> Well, technically the target register is still defined for the GICv3
> >> distributor, but just RES0 if affinity routing is enabled.
> > 
> > Shouldn't we support that then (or do we do this already via a call to
> > a RAZ handle function in the register table instead)?
> 
> Yes:
> 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> 
> > 
> >> But I can of course easily add a _v2_ in here.
> >>
> >> While I look at the function, it makes me wonder if the abstraction for
> >> the affinity change call is actually correct at all. In contrast to the
> >> other vgic_v<n>_* functions this one is about the _emulated_ VGIC model,
> >> not the hardware GIC version.
> >> Also we actually only have this one user here, the other call is about
> >> initializing the affinity setting, for which this function is really
> >> overkill.
> > 
> > How is it overkill?  In that it takes locks which are not necessary?
> 
> Well, yes, and the diff for the init part looks like:
> (pls excuse my stupid mailer for breaking the lines)
> 
> @@ -154,6 +154,7 @@ out:
> int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
> {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
>  	int i;
> 
>  	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
> @@ -174,10 +175,11 @@ int kvm_vgic_dist_init(struct kvm *kvm, unsigned
> int nr_spis)
>  		INIT_LIST_HEAD(&irq->ap_list);
>  		spin_lock_init(&irq->irq_lock);
>  		irq->vcpu = NULL;
> +		irq->target_vcpu = vcpu0;
>  		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
> -			vgic_v2_irq_change_affinity(kvm, irq->intid, 0);
> +			irq->targets = 0;
>  		else
> -			vgic_v3_irq_change_affinity(kvm, irq->intid, 0);
> +			irq->mpidr = 0;
>  	}
>  	return 0;
>  }
> 
> The amended MMIO handling part for the v3 IROUTER register looks similar
> (call to the function replaced with lock; assignment; unlock;). Also the
> v2 implementation is still shorter than the original function.
> So I am tempted to keep the change I just did in the next version.

looks fine to me.

> 
> >> So what about we move the content of the change_affinity function in
> >> here (same for the v3 case later), and tackle the init case separately
> >> (which is trivial)?
> > 
> > I don't think there's much to gain in moving the code into the function,
> > on the contrary, but you could move the function into this file and make
> > it static.
> > 
> > So, you're saying that the current _vX_ functions we have denote the
> > hardware version, not the emulated version, so that would be wrong to do
> > here?
> 
> Yes, at least for everything in vgic/vgic-v[23].c. So having
> vgic_v2_irq_change_affinity() in there is not right.
> 

ok.  I would still like the change_affinity logic in a separate static
function, but you can call it and place it whereever you like :)

-Christoffer

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

* [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
@ 2016-04-12 15:26             ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 15:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 12, 2016 at 04:18:49PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 12/04/16 14:18, Christoffer Dall wrote:
> > On Mon, Apr 11, 2016 at 01:10:24PM +0100, Andre Przywara wrote:
> >> On 31/03/16 12:31, Christoffer Dall wrote:
> >>> On Fri, Mar 25, 2016 at 02:04:43AM +0000, Andre Przywara wrote:
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> ---
> >>>>  virt/kvm/arm/vgic/vgic_mmio.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
> >>>>  1 file changed, 42 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >>>> index 76657ce..cde153f 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >>>> @@ -471,6 +471,47 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> >>>>  	return 0;
> >>>>  }
> >>>>  
> >>>> +static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
> >>>> +				 struct kvm_io_device *this,
> >>>> +				 gpa_t addr, int len, void *val)
> >>>> +{
> >>>> +	struct vgic_io_device *iodev = container_of(this,
> >>>> +						    struct vgic_io_device, dev);
> >>>> +	u32 intid = (addr - iodev->base_addr);
> >>>> +	int i;
> >>>> +
> >>>> +	if (iodev->redist_vcpu)
> >>>> +		vcpu = iodev->redist_vcpu;
> >>>> +
> >>>> +	for (i = 0; i < len; i++) {
> >>>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >>>> +
> >>>> +		((u8 *)val)[i] = irq->targets;
> >>>> +	}
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> >>>> +static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
> >>>> +				  struct kvm_io_device *this,
> >>>> +				  gpa_t addr, int len, const void *val)
> >>>> +{
> >>>> +	struct vgic_io_device *iodev = container_of(this,
> >>>> +						    struct vgic_io_device, dev);
> >>>> +	u32 intid = (addr - iodev->base_addr);
> >>>> +	int i;
> >>>> +
> >>>> +	/* GICD_ITARGETSR[0-7] are read-only */
> >>>> +	if (intid < VGIC_NR_PRIVATE_IRQS)
> >>>> +		return 0;
> >>>> +
> >>>> +	for (i = 0; i < len; i++)
> >>>> +		vgic_v2_irq_change_affinity(vcpu->kvm, intid + i,
> >>>> +					    ((u8 *)val)[i]);
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> >>>
> >>> these functions are v2 specific but are in a generic file and are not
> >>> named anything specific to v2?
> >>
> >> Well, technically the target register is still defined for the GICv3
> >> distributor, but just RES0 if affinity routing is enabled.
> > 
> > Shouldn't we support that then (or do we do this already via a call to
> > a RAZ handle function in the register table instead)?
> 
> Yes:
> 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> 
> > 
> >> But I can of course easily add a _v2_ in here.
> >>
> >> While I look at the function, it makes me wonder if the abstraction for
> >> the affinity change call is actually correct at all. In contrast to the
> >> other vgic_v<n>_* functions this one is about the _emulated_ VGIC model,
> >> not the hardware GIC version.
> >> Also we actually only have this one user here, the other call is about
> >> initializing the affinity setting, for which this function is really
> >> overkill.
> > 
> > How is it overkill?  In that it takes locks which are not necessary?
> 
> Well, yes, and the diff for the init part looks like:
> (pls excuse my stupid mailer for breaking the lines)
> 
> @@ -154,6 +154,7 @@ out:
> int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
> {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
>  	int i;
> 
>  	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
> @@ -174,10 +175,11 @@ int kvm_vgic_dist_init(struct kvm *kvm, unsigned
> int nr_spis)
>  		INIT_LIST_HEAD(&irq->ap_list);
>  		spin_lock_init(&irq->irq_lock);
>  		irq->vcpu = NULL;
> +		irq->target_vcpu = vcpu0;
>  		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
> -			vgic_v2_irq_change_affinity(kvm, irq->intid, 0);
> +			irq->targets = 0;
>  		else
> -			vgic_v3_irq_change_affinity(kvm, irq->intid, 0);
> +			irq->mpidr = 0;
>  	}
>  	return 0;
>  }
> 
> The amended MMIO handling part for the v3 IROUTER register looks similar
> (call to the function replaced with lock; assignment; unlock;). Also the
> v2 implementation is still shorter than the original function.
> So I am tempted to keep the change I just did in the next version.

looks fine to me.

> 
> >> So what about we move the content of the change_affinity function in
> >> here (same for the v3 case later), and tackle the init case separately
> >> (which is trivial)?
> > 
> > I don't think there's much to gain in moving the code into the function,
> > on the contrary, but you could move the function into this file and make
> > it static.
> > 
> > So, you're saying that the current _vX_ functions we have denote the
> > hardware version, not the emulated version, so that would be wrong to do
> > here?
> 
> Yes, at least for everything in vgic/vgic-v[23].c. So having
> vgic_v2_irq_change_affinity() in there is not right.
> 

ok.  I would still like the change_affinity logic in a separate static
function, but you can call it and place it whereever you like :)

-Christoffer

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

* Re: [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-04-12 12:50         ` Christoffer Dall
@ 2016-04-12 15:56           ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2016-04-12 15:56 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara
  Cc: Eric Auger, linux-arm-kernel, kvmarm, kvm

On 12/04/16 13:50, Christoffer Dall wrote:
> On Mon, Apr 11, 2016 at 11:53:21AM +0100, Andre Przywara wrote:
>> Hi Christoffer,
>>
>> On 31/03/16 10:08, Christoffer Dall wrote:
>>> Hi Andre,
>>>
>>> [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
>>>
>>> On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
>>>> We register each register group of the distributor and redistributors
>>>> as separate regions of the kvm-io-bus framework. This way calls get
>>>> directly handed over to the actual handler.
>>>> This puts a lot more regions into kvm-io-bus than what we use at the
>>>> moment on other architectures, so we will probably need to revisit the
>>>> implementation of the framework later to be more efficient.
>>>
>>> Looking more carefully at the KVM IO bus stuff, it looks like it is
>>> indeed designed to be a *per device* thing you register, not a *per
>>> register* thing.
>>>
>>> My comments to Vladimir's bug report notwithstanding, there's still a
>>> choice here to:
>>>
>>> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
>>>
>>> 2) Build a KVM architectureal generic framework on top of the IO bus
>>> framework to handle individual register regions.
>>>
>>> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
>>> and handle the individual register region business locally within the
>>> arm/vgic code.
>>>
>>>
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>>> ---
>>>>  include/kvm/vgic/vgic.h       |   9 ++
>>>>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
>>>>  3 files changed, 250 insertions(+)
>>>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>>>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
>>>>
>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>>>> index 2ce9b4a..a8262c7 100644
>>>> --- a/include/kvm/vgic/vgic.h
>>>> +++ b/include/kvm/vgic/vgic.h
>>>> @@ -106,6 +106,12 @@ struct vgic_irq {
>>>>  	enum vgic_irq_config config;	/* Level or edge */
>>>>  };
>>>>  
>>>> +struct vgic_io_device {
>>>> +	gpa_t base_addr;
>>>> +	struct kvm_vcpu *redist_vcpu;
>>>> +	struct kvm_io_device dev;
>>>> +};
>>>> +
>>>>  struct vgic_dist {
>>>>  	bool			in_kernel;
>>>>  	bool			ready;
>>>> @@ -132,6 +138,9 @@ struct vgic_dist {
>>>>  	u32			enabled;
>>>>  
>>>>  	struct vgic_irq		*spis;
>>>> +
>>>> +	struct vgic_io_device	*dist_iodevs;
>>>> +	struct vgic_io_device	*redist_iodevs;
>>>>  };
>>>>  
>>>>  struct vgic_v2_cpu_if {
>>>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>>>> new file mode 100644
>>>> index 0000000..26c46e7
>>>> --- /dev/null
>>>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>>>> @@ -0,0 +1,194 @@
>>>> +/*
>>>> + * VGIC MMIO handling functions
>>>> + *
>>>> + * 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.
>>>> + */
>>>> +
>>>> +#include <linux/kvm.h>
>>>> +#include <linux/kvm_host.h>
>>>> +#include <kvm/iodev.h>
>>>> +#include <kvm/vgic/vgic.h>
>>>> +#include <linux/bitops.h>
>>>> +#include <linux/irqchip/arm-gic.h>
>>>> +
>>>> +#include "vgic.h"
>>>> +#include "vgic_mmio.h"
>>>> +
>>>> +void write_mask32(u32 value, int offset, int len, void *val)
>>>> +{
>>>> +	value = cpu_to_le32(value) >> (offset * 8);
>>>> +	memcpy(val, &value, len);
>>>> +}
>>>> +
>>>> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
>>>> +{
>>>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>>>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
>>>> +	return origvalue;
>>>> +}
>>>> +
>>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>>>> +void write_mask64(u64 value, int offset, int len, void *val)
>>>> +{
>>>> +	value = cpu_to_le64(value) >> (offset * 8);
>>>> +	memcpy(val, &value, len);
>>>> +}
>>>> +
>>>> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
>>>
>>> I'm confuses in general.  Can you explain what these mask functions do
>>> overall at some higher level?
>>
>> They do what you already guessed: take care about masking and endianness.
>>
>>> I also keep having a feeling that mixing endianness stuff into the
>>> emulation code itself is the wrong way to go about it.
>>
>> I agree.
>>
>>>  The emulation
>>> code should just deal with register values of varying length and the
>>> interface to the VGIC should abstract all endianness nonsense for us,
>>> but I also think I've lost this argument some time in the past.  Sigh.
> 
> I tend to agree with this.  Who did you loose this argument against and
> do you have a pointer?
> 
>>>
>>> But, is the maximum read/write unit for any MMIO access not a 64-bit
>>> value?  So why can't we let the VGIC emulation code simply take/return a
>>> u64 which is then masked off/morphed into the right endianness outside
>>> the VGIC code?
>>
>> The main problem is that the interface for kvm_io_bus is (int len, void
>> *val).
> 
> That could be solved by always just doing a (u64) conversion on the
> caller/receiver side.  E.g.
> 
> int vgic_handle_mmio_access(..., int len, void *val, bool is_write)
> {
> 	u64 data;
> 
> 	if (unsupported_vgic_len(len))
> 		return -ENXIO;
> 
> 	if (is_write)
> 		data = mmio_read_buf(val, len);
> 
> 	// data is now just some data of some lenght in a typed register
> 
> 	call_range_handler(vcpu, &data, len, ...);
> 
> 	if (!is_write)
> 		mmio_write_buf(val, len, data);
> }
> 
> (and share the mmio_ functions in a header file between mmio.c and
> consumers of the packed data).
> 
> The idea would be that the gic is just emulation code in C, which can be
> compiled to some endianness, and we really don't care about how it's
> physically stored in memory.
> 
> 
> 
>> And since the guest's MMIO access can be of different length, we need to
>> take care of this in any case (since we need to know how many IRQs we
>> need to update). So we cannot get rid of the length parameter.
> 
> no we cannot, but we can use a typed pointer instead of a void pointer
> everywhere in the vgic code, since the max access we're going to support
> is 64 bits.
> 
>> I guess what we could do is to either:
>> a) Declare the VGIC as purely little endian (which it really is, AFAIK).
>> We care about the necessary endianness conversion in mmio.c before
>> invoking the kvm_io_bus framework. But that means that we need to deal
>> with the _host's_ endianness in the VGIC emulation.
>> I think this is very close to what we currently do.    OR
>> b) Declare our VGIC emulation as always using the host's endianess. We
>> wouldn't need to care about endianness in the VGIC code anymore (is that
>> actually true?) We convert the MMIO traps (which are little endian
>> always) into the host's endianness before passing it on to kvm-io-bus.
>>
>> I just see that this probably adds more to the confusion, oh well...
> 
> No, it doesn't add anymore confusion.  I think option (b) is what we
> should do, unless it's not possible for some reason that I fail to
> realize at this very moment.
> 
> If all your pointers in the vgic emulation code are always typed, then I
> don't see why you'd have to worry about endianness anywhere?
> 
> The only place we should worry about endianness is the
> vcpu_data_guest_to_host() and vcpu_data_host_to_guest() functions.
> Doing it anywhere else as well is an indication that we're doing
> something wrong.

That seems sensible to me. This should define a frontier where the
access to the GIC is always expected in LE mode, but we implement the
GIC using the host endianness. We have to make sure that no data
structure gets passed outside of this interface (and that includes
userspace access).

This works fine for MMIO, but I'm more worried of memory-based
interfaces that we get with GICv3 and the ITS, specially with migration.
Property table is fine (byte access), but pending table can be slightly
more tricky (bit position in words). And then we get to the ITS tables,
which need a standard representation. Maybe it is too early for that,
but it is worth keeping it in mind.

Thanks,

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

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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-04-12 15:56           ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2016-04-12 15:56 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 13:50, Christoffer Dall wrote:
> On Mon, Apr 11, 2016 at 11:53:21AM +0100, Andre Przywara wrote:
>> Hi Christoffer,
>>
>> On 31/03/16 10:08, Christoffer Dall wrote:
>>> Hi Andre,
>>>
>>> [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
>>>
>>> On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
>>>> We register each register group of the distributor and redistributors
>>>> as separate regions of the kvm-io-bus framework. This way calls get
>>>> directly handed over to the actual handler.
>>>> This puts a lot more regions into kvm-io-bus than what we use at the
>>>> moment on other architectures, so we will probably need to revisit the
>>>> implementation of the framework later to be more efficient.
>>>
>>> Looking more carefully at the KVM IO bus stuff, it looks like it is
>>> indeed designed to be a *per device* thing you register, not a *per
>>> register* thing.
>>>
>>> My comments to Vladimir's bug report notwithstanding, there's still a
>>> choice here to:
>>>
>>> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
>>>
>>> 2) Build a KVM architectureal generic framework on top of the IO bus
>>> framework to handle individual register regions.
>>>
>>> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
>>> and handle the individual register region business locally within the
>>> arm/vgic code.
>>>
>>>
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>>> ---
>>>>  include/kvm/vgic/vgic.h       |   9 ++
>>>>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
>>>>  3 files changed, 250 insertions(+)
>>>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
>>>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
>>>>
>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>>>> index 2ce9b4a..a8262c7 100644
>>>> --- a/include/kvm/vgic/vgic.h
>>>> +++ b/include/kvm/vgic/vgic.h
>>>> @@ -106,6 +106,12 @@ struct vgic_irq {
>>>>  	enum vgic_irq_config config;	/* Level or edge */
>>>>  };
>>>>  
>>>> +struct vgic_io_device {
>>>> +	gpa_t base_addr;
>>>> +	struct kvm_vcpu *redist_vcpu;
>>>> +	struct kvm_io_device dev;
>>>> +};
>>>> +
>>>>  struct vgic_dist {
>>>>  	bool			in_kernel;
>>>>  	bool			ready;
>>>> @@ -132,6 +138,9 @@ struct vgic_dist {
>>>>  	u32			enabled;
>>>>  
>>>>  	struct vgic_irq		*spis;
>>>> +
>>>> +	struct vgic_io_device	*dist_iodevs;
>>>> +	struct vgic_io_device	*redist_iodevs;
>>>>  };
>>>>  
>>>>  struct vgic_v2_cpu_if {
>>>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>>>> new file mode 100644
>>>> index 0000000..26c46e7
>>>> --- /dev/null
>>>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>>>> @@ -0,0 +1,194 @@
>>>> +/*
>>>> + * VGIC MMIO handling functions
>>>> + *
>>>> + * 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.
>>>> + */
>>>> +
>>>> +#include <linux/kvm.h>
>>>> +#include <linux/kvm_host.h>
>>>> +#include <kvm/iodev.h>
>>>> +#include <kvm/vgic/vgic.h>
>>>> +#include <linux/bitops.h>
>>>> +#include <linux/irqchip/arm-gic.h>
>>>> +
>>>> +#include "vgic.h"
>>>> +#include "vgic_mmio.h"
>>>> +
>>>> +void write_mask32(u32 value, int offset, int len, void *val)
>>>> +{
>>>> +	value = cpu_to_le32(value) >> (offset * 8);
>>>> +	memcpy(val, &value, len);
>>>> +}
>>>> +
>>>> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
>>>> +{
>>>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
>>>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
>>>> +	return origvalue;
>>>> +}
>>>> +
>>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>>>> +void write_mask64(u64 value, int offset, int len, void *val)
>>>> +{
>>>> +	value = cpu_to_le64(value) >> (offset * 8);
>>>> +	memcpy(val, &value, len);
>>>> +}
>>>> +
>>>> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
>>>
>>> I'm confuses in general.  Can you explain what these mask functions do
>>> overall at some higher level?
>>
>> They do what you already guessed: take care about masking and endianness.
>>
>>> I also keep having a feeling that mixing endianness stuff into the
>>> emulation code itself is the wrong way to go about it.
>>
>> I agree.
>>
>>>  The emulation
>>> code should just deal with register values of varying length and the
>>> interface to the VGIC should abstract all endianness nonsense for us,
>>> but I also think I've lost this argument some time in the past.  Sigh.
> 
> I tend to agree with this.  Who did you loose this argument against and
> do you have a pointer?
> 
>>>
>>> But, is the maximum read/write unit for any MMIO access not a 64-bit
>>> value?  So why can't we let the VGIC emulation code simply take/return a
>>> u64 which is then masked off/morphed into the right endianness outside
>>> the VGIC code?
>>
>> The main problem is that the interface for kvm_io_bus is (int len, void
>> *val).
> 
> That could be solved by always just doing a (u64) conversion on the
> caller/receiver side.  E.g.
> 
> int vgic_handle_mmio_access(..., int len, void *val, bool is_write)
> {
> 	u64 data;
> 
> 	if (unsupported_vgic_len(len))
> 		return -ENXIO;
> 
> 	if (is_write)
> 		data = mmio_read_buf(val, len);
> 
> 	// data is now just some data of some lenght in a typed register
> 
> 	call_range_handler(vcpu, &data, len, ...);
> 
> 	if (!is_write)
> 		mmio_write_buf(val, len, data);
> }
> 
> (and share the mmio_ functions in a header file between mmio.c and
> consumers of the packed data).
> 
> The idea would be that the gic is just emulation code in C, which can be
> compiled to some endianness, and we really don't care about how it's
> physically stored in memory.
> 
> 
> 
>> And since the guest's MMIO access can be of different length, we need to
>> take care of this in any case (since we need to know how many IRQs we
>> need to update). So we cannot get rid of the length parameter.
> 
> no we cannot, but we can use a typed pointer instead of a void pointer
> everywhere in the vgic code, since the max access we're going to support
> is 64 bits.
> 
>> I guess what we could do is to either:
>> a) Declare the VGIC as purely little endian (which it really is, AFAIK).
>> We care about the necessary endianness conversion in mmio.c before
>> invoking the kvm_io_bus framework. But that means that we need to deal
>> with the _host's_ endianness in the VGIC emulation.
>> I think this is very close to what we currently do.    OR
>> b) Declare our VGIC emulation as always using the host's endianess. We
>> wouldn't need to care about endianness in the VGIC code anymore (is that
>> actually true?) We convert the MMIO traps (which are little endian
>> always) into the host's endianness before passing it on to kvm-io-bus.
>>
>> I just see that this probably adds more to the confusion, oh well...
> 
> No, it doesn't add anymore confusion.  I think option (b) is what we
> should do, unless it's not possible for some reason that I fail to
> realize at this very moment.
> 
> If all your pointers in the vgic emulation code are always typed, then I
> don't see why you'd have to worry about endianness anywhere?
> 
> The only place we should worry about endianness is the
> vcpu_data_guest_to_host() and vcpu_data_host_to_guest() functions.
> Doing it anywhere else as well is an indication that we're doing
> something wrong.

That seems sensible to me. This should define a frontier where the
access to the GIC is always expected in LE mode, but we implement the
GIC using the host endianness. We have to make sure that no data
structure gets passed outside of this interface (and that includes
userspace access).

This works fine for MMIO, but I'm more worried of memory-based
interfaces that we get with GICv3 and the ITS, specially with migration.
Property table is fine (byte access), but pending table can be slightly
more tricky (bit position in words). And then we get to the ITS tables,
which need a standard representation. Maybe it is too early for that,
but it is worth keeping it in mind.

Thanks,

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

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

* Re: [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-04-12 15:56           ` Marc Zyngier
@ 2016-04-12 17:26             ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 17:26 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: Andre Przywara, kvm, kvmarm, linux-arm-kernel

On Tue, Apr 12, 2016 at 04:56:08PM +0100, Marc Zyngier wrote:
> On 12/04/16 13:50, Christoffer Dall wrote:
> > On Mon, Apr 11, 2016 at 11:53:21AM +0100, Andre Przywara wrote:
> >> Hi Christoffer,
> >>
> >> On 31/03/16 10:08, Christoffer Dall wrote:
> >>> Hi Andre,
> >>>
> >>> [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
> >>>
> >>> On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
> >>>> We register each register group of the distributor and redistributors
> >>>> as separate regions of the kvm-io-bus framework. This way calls get
> >>>> directly handed over to the actual handler.
> >>>> This puts a lot more regions into kvm-io-bus than what we use at the
> >>>> moment on other architectures, so we will probably need to revisit the
> >>>> implementation of the framework later to be more efficient.
> >>>
> >>> Looking more carefully at the KVM IO bus stuff, it looks like it is
> >>> indeed designed to be a *per device* thing you register, not a *per
> >>> register* thing.
> >>>
> >>> My comments to Vladimir's bug report notwithstanding, there's still a
> >>> choice here to:
> >>>
> >>> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> >>>
> >>> 2) Build a KVM architectureal generic framework on top of the IO bus
> >>> framework to handle individual register regions.
> >>>
> >>> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> >>> and handle the individual register region business locally within the
> >>> arm/vgic code.
> >>>
> >>>
> >>>>
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >>>> ---
> >>>>  include/kvm/vgic/vgic.h       |   9 ++
> >>>>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
> >>>>  3 files changed, 250 insertions(+)
> >>>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
> >>>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
> >>>>
> >>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >>>> index 2ce9b4a..a8262c7 100644
> >>>> --- a/include/kvm/vgic/vgic.h
> >>>> +++ b/include/kvm/vgic/vgic.h
> >>>> @@ -106,6 +106,12 @@ struct vgic_irq {
> >>>>  	enum vgic_irq_config config;	/* Level or edge */
> >>>>  };
> >>>>  
> >>>> +struct vgic_io_device {
> >>>> +	gpa_t base_addr;
> >>>> +	struct kvm_vcpu *redist_vcpu;
> >>>> +	struct kvm_io_device dev;
> >>>> +};
> >>>> +
> >>>>  struct vgic_dist {
> >>>>  	bool			in_kernel;
> >>>>  	bool			ready;
> >>>> @@ -132,6 +138,9 @@ struct vgic_dist {
> >>>>  	u32			enabled;
> >>>>  
> >>>>  	struct vgic_irq		*spis;
> >>>> +
> >>>> +	struct vgic_io_device	*dist_iodevs;
> >>>> +	struct vgic_io_device	*redist_iodevs;
> >>>>  };
> >>>>  
> >>>>  struct vgic_v2_cpu_if {
> >>>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >>>> new file mode 100644
> >>>> index 0000000..26c46e7
> >>>> --- /dev/null
> >>>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >>>> @@ -0,0 +1,194 @@
> >>>> +/*
> >>>> + * VGIC MMIO handling functions
> >>>> + *
> >>>> + * 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.
> >>>> + */
> >>>> +
> >>>> +#include <linux/kvm.h>
> >>>> +#include <linux/kvm_host.h>
> >>>> +#include <kvm/iodev.h>
> >>>> +#include <kvm/vgic/vgic.h>
> >>>> +#include <linux/bitops.h>
> >>>> +#include <linux/irqchip/arm-gic.h>
> >>>> +
> >>>> +#include "vgic.h"
> >>>> +#include "vgic_mmio.h"
> >>>> +
> >>>> +void write_mask32(u32 value, int offset, int len, void *val)
> >>>> +{
> >>>> +	value = cpu_to_le32(value) >> (offset * 8);
> >>>> +	memcpy(val, &value, len);
> >>>> +}
> >>>> +
> >>>> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
> >>>> +{
> >>>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
> >>>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
> >>>> +	return origvalue;
> >>>> +}
> >>>> +
> >>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> >>>> +void write_mask64(u64 value, int offset, int len, void *val)
> >>>> +{
> >>>> +	value = cpu_to_le64(value) >> (offset * 8);
> >>>> +	memcpy(val, &value, len);
> >>>> +}
> >>>> +
> >>>> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
> >>>
> >>> I'm confuses in general.  Can you explain what these mask functions do
> >>> overall at some higher level?
> >>
> >> They do what you already guessed: take care about masking and endianness.
> >>
> >>> I also keep having a feeling that mixing endianness stuff into the
> >>> emulation code itself is the wrong way to go about it.
> >>
> >> I agree.
> >>
> >>>  The emulation
> >>> code should just deal with register values of varying length and the
> >>> interface to the VGIC should abstract all endianness nonsense for us,
> >>> but I also think I've lost this argument some time in the past.  Sigh.
> > 
> > I tend to agree with this.  Who did you loose this argument against and
> > do you have a pointer?
> > 
> >>>
> >>> But, is the maximum read/write unit for any MMIO access not a 64-bit
> >>> value?  So why can't we let the VGIC emulation code simply take/return a
> >>> u64 which is then masked off/morphed into the right endianness outside
> >>> the VGIC code?
> >>
> >> The main problem is that the interface for kvm_io_bus is (int len, void
> >> *val).
> > 
> > That could be solved by always just doing a (u64) conversion on the
> > caller/receiver side.  E.g.
> > 
> > int vgic_handle_mmio_access(..., int len, void *val, bool is_write)
> > {
> > 	u64 data;
> > 
> > 	if (unsupported_vgic_len(len))
> > 		return -ENXIO;
> > 
> > 	if (is_write)
> > 		data = mmio_read_buf(val, len);
> > 
> > 	// data is now just some data of some lenght in a typed register
> > 
> > 	call_range_handler(vcpu, &data, len, ...);
> > 
> > 	if (!is_write)
> > 		mmio_write_buf(val, len, data);
> > }
> > 
> > (and share the mmio_ functions in a header file between mmio.c and
> > consumers of the packed data).
> > 
> > The idea would be that the gic is just emulation code in C, which can be
> > compiled to some endianness, and we really don't care about how it's
> > physically stored in memory.
> > 
> > 
> > 
> >> And since the guest's MMIO access can be of different length, we need to
> >> take care of this in any case (since we need to know how many IRQs we
> >> need to update). So we cannot get rid of the length parameter.
> > 
> > no we cannot, but we can use a typed pointer instead of a void pointer
> > everywhere in the vgic code, since the max access we're going to support
> > is 64 bits.
> > 
> >> I guess what we could do is to either:
> >> a) Declare the VGIC as purely little endian (which it really is, AFAIK).
> >> We care about the necessary endianness conversion in mmio.c before
> >> invoking the kvm_io_bus framework. But that means that we need to deal
> >> with the _host's_ endianness in the VGIC emulation.
> >> I think this is very close to what we currently do.    OR
> >> b) Declare our VGIC emulation as always using the host's endianess. We
> >> wouldn't need to care about endianness in the VGIC code anymore (is that
> >> actually true?) We convert the MMIO traps (which are little endian
> >> always) into the host's endianness before passing it on to kvm-io-bus.
> >>
> >> I just see that this probably adds more to the confusion, oh well...
> > 
> > No, it doesn't add anymore confusion.  I think option (b) is what we
> > should do, unless it's not possible for some reason that I fail to
> > realize at this very moment.
> > 
> > If all your pointers in the vgic emulation code are always typed, then I
> > don't see why you'd have to worry about endianness anywhere?
> > 
> > The only place we should worry about endianness is the
> > vcpu_data_guest_to_host() and vcpu_data_host_to_guest() functions.
> > Doing it anywhere else as well is an indication that we're doing
> > something wrong.
> 
> That seems sensible to me. This should define a frontier where the
> access to the GIC is always expected in LE mode, but we implement the
> GIC using the host endianness. We have to make sure that no data
> structure gets passed outside of this interface (and that includes
> userspace access).

I think userspace accesses are fine.  That's another external interface
where you can handle whatever endianness conversion there.

> 
> This works fine for MMIO, but I'm more worried of memory-based
> interfaces that we get with GICv3 and the ITS, specially with migration.
> Property table is fine (byte access), but pending table can be slightly
> more tricky (bit position in words). And then we get to the ITS tables,
> which need a standard representation. Maybe it is too early for that,
> but it is worth keeping it in mind.
> 
I didn't consider the visible-to-guest in-memory data structures.  We
should define anything that would be affected by endianness strictly,
but I still think we're limited to dealing with endianness in (1) the
MMIO interface, (2) userspace access, (3) flushing the in-kernel cache
to memory data structures.

That's much better than every time we fix some part of the emulation
code, it touches some magic endianness function/trick, and you have to
follow a trail a mile long to figure out all the conversions and whether
it's right or not.  At least I have found this very hard in the past.

Thanks,
-Christoffer

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

* [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-04-12 17:26             ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-12 17:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 12, 2016 at 04:56:08PM +0100, Marc Zyngier wrote:
> On 12/04/16 13:50, Christoffer Dall wrote:
> > On Mon, Apr 11, 2016 at 11:53:21AM +0100, Andre Przywara wrote:
> >> Hi Christoffer,
> >>
> >> On 31/03/16 10:08, Christoffer Dall wrote:
> >>> Hi Andre,
> >>>
> >>> [cc'ing Paolo here for his thoughts on the KVM IO bus framework]
> >>>
> >>> On Fri, Mar 25, 2016 at 02:04:35AM +0000, Andre Przywara wrote:
> >>>> We register each register group of the distributor and redistributors
> >>>> as separate regions of the kvm-io-bus framework. This way calls get
> >>>> directly handed over to the actual handler.
> >>>> This puts a lot more regions into kvm-io-bus than what we use at the
> >>>> moment on other architectures, so we will probably need to revisit the
> >>>> implementation of the framework later to be more efficient.
> >>>
> >>> Looking more carefully at the KVM IO bus stuff, it looks like it is
> >>> indeed designed to be a *per device* thing you register, not a *per
> >>> register* thing.
> >>>
> >>> My comments to Vladimir's bug report notwithstanding, there's still a
> >>> choice here to:
> >>>
> >>> 1) Expand/modify the KVM IO bus framework to take an arbitrary number of devices
> >>>
> >>> 2) Build a KVM architectureal generic framework on top of the IO bus
> >>> framework to handle individual register regions.
> >>>
> >>> 3) Stick with what we had before, do not modify the KVM IO bus stuff,
> >>> and handle the individual register region business locally within the
> >>> arm/vgic code.
> >>>
> >>>
> >>>>
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >>>> ---
> >>>>  include/kvm/vgic/vgic.h       |   9 ++
> >>>>  virt/kvm/arm/vgic/vgic_mmio.c | 194 ++++++++++++++++++++++++++++++++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic_mmio.h |  47 ++++++++++
> >>>>  3 files changed, 250 insertions(+)
> >>>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
> >>>>  create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
> >>>>
> >>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >>>> index 2ce9b4a..a8262c7 100644
> >>>> --- a/include/kvm/vgic/vgic.h
> >>>> +++ b/include/kvm/vgic/vgic.h
> >>>> @@ -106,6 +106,12 @@ struct vgic_irq {
> >>>>  	enum vgic_irq_config config;	/* Level or edge */
> >>>>  };
> >>>>  
> >>>> +struct vgic_io_device {
> >>>> +	gpa_t base_addr;
> >>>> +	struct kvm_vcpu *redist_vcpu;
> >>>> +	struct kvm_io_device dev;
> >>>> +};
> >>>> +
> >>>>  struct vgic_dist {
> >>>>  	bool			in_kernel;
> >>>>  	bool			ready;
> >>>> @@ -132,6 +138,9 @@ struct vgic_dist {
> >>>>  	u32			enabled;
> >>>>  
> >>>>  	struct vgic_irq		*spis;
> >>>> +
> >>>> +	struct vgic_io_device	*dist_iodevs;
> >>>> +	struct vgic_io_device	*redist_iodevs;
> >>>>  };
> >>>>  
> >>>>  struct vgic_v2_cpu_if {
> >>>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> >>>> new file mode 100644
> >>>> index 0000000..26c46e7
> >>>> --- /dev/null
> >>>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> >>>> @@ -0,0 +1,194 @@
> >>>> +/*
> >>>> + * VGIC MMIO handling functions
> >>>> + *
> >>>> + * 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.
> >>>> + */
> >>>> +
> >>>> +#include <linux/kvm.h>
> >>>> +#include <linux/kvm_host.h>
> >>>> +#include <kvm/iodev.h>
> >>>> +#include <kvm/vgic/vgic.h>
> >>>> +#include <linux/bitops.h>
> >>>> +#include <linux/irqchip/arm-gic.h>
> >>>> +
> >>>> +#include "vgic.h"
> >>>> +#include "vgic_mmio.h"
> >>>> +
> >>>> +void write_mask32(u32 value, int offset, int len, void *val)
> >>>> +{
> >>>> +	value = cpu_to_le32(value) >> (offset * 8);
> >>>> +	memcpy(val, &value, len);
> >>>> +}
> >>>> +
> >>>> +u32 mask32(u32 origvalue, int offset, int len, const void *val)
> >>>> +{
> >>>> +	origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
> >>>> +	memcpy((char *)&origvalue + (offset * 8), val, len);
> >>>> +	return origvalue;
> >>>> +}
> >>>> +
> >>>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> >>>> +void write_mask64(u64 value, int offset, int len, void *val)
> >>>> +{
> >>>> +	value = cpu_to_le64(value) >> (offset * 8);
> >>>> +	memcpy(val, &value, len);
> >>>> +}
> >>>> +
> >>>> +/* FIXME: I am clearly misguided here, there must be some saner way ... */
> >>>
> >>> I'm confuses in general.  Can you explain what these mask functions do
> >>> overall at some higher level?
> >>
> >> They do what you already guessed: take care about masking and endianness.
> >>
> >>> I also keep having a feeling that mixing endianness stuff into the
> >>> emulation code itself is the wrong way to go about it.
> >>
> >> I agree.
> >>
> >>>  The emulation
> >>> code should just deal with register values of varying length and the
> >>> interface to the VGIC should abstract all endianness nonsense for us,
> >>> but I also think I've lost this argument some time in the past.  Sigh.
> > 
> > I tend to agree with this.  Who did you loose this argument against and
> > do you have a pointer?
> > 
> >>>
> >>> But, is the maximum read/write unit for any MMIO access not a 64-bit
> >>> value?  So why can't we let the VGIC emulation code simply take/return a
> >>> u64 which is then masked off/morphed into the right endianness outside
> >>> the VGIC code?
> >>
> >> The main problem is that the interface for kvm_io_bus is (int len, void
> >> *val).
> > 
> > That could be solved by always just doing a (u64) conversion on the
> > caller/receiver side.  E.g.
> > 
> > int vgic_handle_mmio_access(..., int len, void *val, bool is_write)
> > {
> > 	u64 data;
> > 
> > 	if (unsupported_vgic_len(len))
> > 		return -ENXIO;
> > 
> > 	if (is_write)
> > 		data = mmio_read_buf(val, len);
> > 
> > 	// data is now just some data of some lenght in a typed register
> > 
> > 	call_range_handler(vcpu, &data, len, ...);
> > 
> > 	if (!is_write)
> > 		mmio_write_buf(val, len, data);
> > }
> > 
> > (and share the mmio_ functions in a header file between mmio.c and
> > consumers of the packed data).
> > 
> > The idea would be that the gic is just emulation code in C, which can be
> > compiled to some endianness, and we really don't care about how it's
> > physically stored in memory.
> > 
> > 
> > 
> >> And since the guest's MMIO access can be of different length, we need to
> >> take care of this in any case (since we need to know how many IRQs we
> >> need to update). So we cannot get rid of the length parameter.
> > 
> > no we cannot, but we can use a typed pointer instead of a void pointer
> > everywhere in the vgic code, since the max access we're going to support
> > is 64 bits.
> > 
> >> I guess what we could do is to either:
> >> a) Declare the VGIC as purely little endian (which it really is, AFAIK).
> >> We care about the necessary endianness conversion in mmio.c before
> >> invoking the kvm_io_bus framework. But that means that we need to deal
> >> with the _host's_ endianness in the VGIC emulation.
> >> I think this is very close to what we currently do.    OR
> >> b) Declare our VGIC emulation as always using the host's endianess. We
> >> wouldn't need to care about endianness in the VGIC code anymore (is that
> >> actually true?) We convert the MMIO traps (which are little endian
> >> always) into the host's endianness before passing it on to kvm-io-bus.
> >>
> >> I just see that this probably adds more to the confusion, oh well...
> > 
> > No, it doesn't add anymore confusion.  I think option (b) is what we
> > should do, unless it's not possible for some reason that I fail to
> > realize at this very moment.
> > 
> > If all your pointers in the vgic emulation code are always typed, then I
> > don't see why you'd have to worry about endianness anywhere?
> > 
> > The only place we should worry about endianness is the
> > vcpu_data_guest_to_host() and vcpu_data_host_to_guest() functions.
> > Doing it anywhere else as well is an indication that we're doing
> > something wrong.
> 
> That seems sensible to me. This should define a frontier where the
> access to the GIC is always expected in LE mode, but we implement the
> GIC using the host endianness. We have to make sure that no data
> structure gets passed outside of this interface (and that includes
> userspace access).

I think userspace accesses are fine.  That's another external interface
where you can handle whatever endianness conversion there.

> 
> This works fine for MMIO, but I'm more worried of memory-based
> interfaces that we get with GICv3 and the ITS, specially with migration.
> Property table is fine (byte access), but pending table can be slightly
> more tricky (bit position in words). And then we get to the ITS tables,
> which need a standard representation. Maybe it is too early for that,
> but it is worth keeping it in mind.
> 
I didn't consider the visible-to-guest in-memory data structures.  We
should define anything that would be affected by endianness strictly,
but I still think we're limited to dealing with endianness in (1) the
MMIO interface, (2) userspace access, (3) flushing the in-kernel cache
to memory data structures.

That's much better than every time we fix some part of the emulation
code, it touches some magic endianness function/trick, and you have to
follow a trail a mile long to figure out all the conversions and whether
it's right or not.  At least I have found this very hard in the past.

Thanks,
-Christoffer

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-03-31 18:30   ` Christoffer Dall
@ 2016-04-13 16:07     ` André Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: André Przywara @ 2016-04-13 16:07 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On 31/03/16 19:30, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:23AM +0000, Andre Przywara wrote:
>> This series is a joint effort to re-implement KVM's GIC emulation.
>>
>> While the current implementation is centered around providing
>> efficient MMIO emulation, the hot path for most guests is actually
>> the guest entry and exit, which currently is rather costly.
>> Also the existing emulation has a global distributor lock, which
>> quickly becomes a bottleneck once the number of VCPUs increases.
>> Additionally the emulation was originally designed for GICv2, adding
>> GICv3 ITS emulation support to this proved to be rather painful.
>> Last, but not least the existing code became less and less
>> maintainable, with many special cases handled explicitly.
>>
>> The new implementation is build around a struct vgic_irq data data
>> structure, which holds all information about a virtual interrupt.
>> Interruts which should be injected are hold in a per-VCPU list, this
>> make the entry/exit path much more efficient. Also the new structure
>> allows to have more fine grained locking - per IRQ and per VCPU -
>> getting rid of the global distributor lock.
>> As a result of the new design ITS emulation fits in more nicely, the
>> respective code will be provided as a follow-up series.
>>
>> This series implements the same feature set as the existing emulation,
>> as a goodie we now implement priorities correctly.
>> To allow an easy transition with good test coverage, but still maintain
>> stability, both implementations live side by side, selectable via a
>> Kconfig option. The default is the new implementation.
>> If this code proves to be reliable, we will later remove the current
>> implementation with an extra patch set.
>>
>> Please have a look at the series, review it and give the code some
>> serious testing (and possibly debugging). All feedback is appreciated.
>>
> 
> Hmph, starting a guest a couple of times and running hackbench inside
> the guest actually gave me (twice) the following error:
> 
> NMI watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [kworker/0:0:4]

On the host or in the guest?
Can you reproduce it easily? If yes, can you add some lock debugging to
see if we are stuck in a spinlock?

Cheers,
Andre.


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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-04-13 16:07     ` André Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: André Przywara @ 2016-04-13 16:07 UTC (permalink / raw)
  To: linux-arm-kernel

On 31/03/16 19:30, Christoffer Dall wrote:
> On Fri, Mar 25, 2016 at 02:04:23AM +0000, Andre Przywara wrote:
>> This series is a joint effort to re-implement KVM's GIC emulation.
>>
>> While the current implementation is centered around providing
>> efficient MMIO emulation, the hot path for most guests is actually
>> the guest entry and exit, which currently is rather costly.
>> Also the existing emulation has a global distributor lock, which
>> quickly becomes a bottleneck once the number of VCPUs increases.
>> Additionally the emulation was originally designed for GICv2, adding
>> GICv3 ITS emulation support to this proved to be rather painful.
>> Last, but not least the existing code became less and less
>> maintainable, with many special cases handled explicitly.
>>
>> The new implementation is build around a struct vgic_irq data data
>> structure, which holds all information about a virtual interrupt.
>> Interruts which should be injected are hold in a per-VCPU list, this
>> make the entry/exit path much more efficient. Also the new structure
>> allows to have more fine grained locking - per IRQ and per VCPU -
>> getting rid of the global distributor lock.
>> As a result of the new design ITS emulation fits in more nicely, the
>> respective code will be provided as a follow-up series.
>>
>> This series implements the same feature set as the existing emulation,
>> as a goodie we now implement priorities correctly.
>> To allow an easy transition with good test coverage, but still maintain
>> stability, both implementations live side by side, selectable via a
>> Kconfig option. The default is the new implementation.
>> If this code proves to be reliable, we will later remove the current
>> implementation with an extra patch set.
>>
>> Please have a look at the series, review it and give the code some
>> serious testing (and possibly debugging). All feedback is appreciated.
>>
> 
> Hmph, starting a guest a couple of times and running hackbench inside
> the guest actually gave me (twice) the following error:
> 
> NMI watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [kworker/0:0:4]

On the host or in the guest?
Can you reproduce it easily? If yes, can you add some lock debugging to
see if we are stuck in a spinlock?

Cheers,
Andre.

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

* Re: [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
  2016-04-13 16:07     ` André Przywara
@ 2016-04-13 17:24       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-13 17:24 UTC (permalink / raw)
  To: André Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Wed, Apr 13, 2016 at 05:07:56PM +0100, André Przywara wrote:
> On 31/03/16 19:30, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:23AM +0000, Andre Przywara wrote:
> >> This series is a joint effort to re-implement KVM's GIC emulation.
> >>
> >> While the current implementation is centered around providing
> >> efficient MMIO emulation, the hot path for most guests is actually
> >> the guest entry and exit, which currently is rather costly.
> >> Also the existing emulation has a global distributor lock, which
> >> quickly becomes a bottleneck once the number of VCPUs increases.
> >> Additionally the emulation was originally designed for GICv2, adding
> >> GICv3 ITS emulation support to this proved to be rather painful.
> >> Last, but not least the existing code became less and less
> >> maintainable, with many special cases handled explicitly.
> >>
> >> The new implementation is build around a struct vgic_irq data data
> >> structure, which holds all information about a virtual interrupt.
> >> Interruts which should be injected are hold in a per-VCPU list, this
> >> make the entry/exit path much more efficient. Also the new structure
> >> allows to have more fine grained locking - per IRQ and per VCPU -
> >> getting rid of the global distributor lock.
> >> As a result of the new design ITS emulation fits in more nicely, the
> >> respective code will be provided as a follow-up series.
> >>
> >> This series implements the same feature set as the existing emulation,
> >> as a goodie we now implement priorities correctly.
> >> To allow an easy transition with good test coverage, but still maintain
> >> stability, both implementations live side by side, selectable via a
> >> Kconfig option. The default is the new implementation.
> >> If this code proves to be reliable, we will later remove the current
> >> implementation with an extra patch set.
> >>
> >> Please have a look at the series, review it and give the code some
> >> serious testing (and possibly debugging). All feedback is appreciated.
> >>
> > 
> > Hmph, starting a guest a couple of times and running hackbench inside
> > the guest actually gave me (twice) the following error:
> > 
> > NMI watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [kworker/0:0:4]
> 
> On the host or in the guest?

In the guest.

> Can you reproduce it easily? If yes, can you add some lock debugging to
> see if we are stuck in a spinlock?
> 

I'll do this when you've posted a new version. Sound ok?

-Christoffer

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

* [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-04-13 17:24       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-13 17:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 13, 2016 at 05:07:56PM +0100, Andr? Przywara wrote:
> On 31/03/16 19:30, Christoffer Dall wrote:
> > On Fri, Mar 25, 2016 at 02:04:23AM +0000, Andre Przywara wrote:
> >> This series is a joint effort to re-implement KVM's GIC emulation.
> >>
> >> While the current implementation is centered around providing
> >> efficient MMIO emulation, the hot path for most guests is actually
> >> the guest entry and exit, which currently is rather costly.
> >> Also the existing emulation has a global distributor lock, which
> >> quickly becomes a bottleneck once the number of VCPUs increases.
> >> Additionally the emulation was originally designed for GICv2, adding
> >> GICv3 ITS emulation support to this proved to be rather painful.
> >> Last, but not least the existing code became less and less
> >> maintainable, with many special cases handled explicitly.
> >>
> >> The new implementation is build around a struct vgic_irq data data
> >> structure, which holds all information about a virtual interrupt.
> >> Interruts which should be injected are hold in a per-VCPU list, this
> >> make the entry/exit path much more efficient. Also the new structure
> >> allows to have more fine grained locking - per IRQ and per VCPU -
> >> getting rid of the global distributor lock.
> >> As a result of the new design ITS emulation fits in more nicely, the
> >> respective code will be provided as a follow-up series.
> >>
> >> This series implements the same feature set as the existing emulation,
> >> as a goodie we now implement priorities correctly.
> >> To allow an easy transition with good test coverage, but still maintain
> >> stability, both implementations live side by side, selectable via a
> >> Kconfig option. The default is the new implementation.
> >> If this code proves to be reliable, we will later remove the current
> >> implementation with an extra patch set.
> >>
> >> Please have a look at the series, review it and give the code some
> >> serious testing (and possibly debugging). All feedback is appreciated.
> >>
> > 
> > Hmph, starting a guest a couple of times and running hackbench inside
> > the guest actually gave me (twice) the following error:
> > 
> > NMI watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [kworker/0:0:4]
> 
> On the host or in the guest?

In the guest.

> Can you reproduce it easily? If yes, can you add some lock debugging to
> see if we are stuck in a spinlock?
> 

I'll do this when you've posted a new version. Sound ok?

-Christoffer

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

* Re: [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-04-06 14:23         ` Christoffer Dall
@ 2016-04-14 10:53           ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-14 10:53 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hej,

On 06/04/16 15:23, Christoffer Dall wrote:
> On Tue, Apr 05, 2016 at 06:28:55PM +0100, Andre Przywara wrote:
>> Hi,
>>
>> On 29/03/16 22:16, Christoffer Dall wrote:
>>> On Fri, Mar 25, 2016 at 02:04:29AM +0000, Andre Przywara wrote:
>>>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>>>
>>>> Provide a vgic_queue_irq() function which decides whether a given
>>>> IRQ needs to be queued to a VCPU's ap_list.
>>>> This should be called whenever an IRQ became pending or got enabled,
>>>
>>> becomes pending or enabled,
>>>
>>>> either as a result of userspace injection, from in-kernel emulated
>>>> devices like the architected timer or from MMIO accesses to the
>>>> distributor emulation.
>>>> Also provides the necessary functions to allow userland to inject an
>>>> IRQ to a guest.
>>>
>>> Since this is the first code that starts using our locking mechanism, we
>>> add some (hopefully) clear documentation of our locking strategy and
>>> requirements along with this patch.
>>>
>>>> [Andre: refactor out vgic_queue_irq()]
>>>>
>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>>  include/kvm/vgic/vgic.h  |   3 +
>>>>  virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.h |   1 +
>>>>  3 files changed, 185 insertions(+)
>>>>
>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>>>> index 659f8b1..f32b284 100644
>>>> --- a/include/kvm/vgic/vgic.h
>>>> +++ b/include/kvm/vgic/vgic.h
>>>> @@ -178,6 +178,9 @@ struct vgic_cpu {
>>>>  	struct list_head ap_list_head;
>>>>  };
>>>>  
>>>> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>>> +			bool level);
>>>> +
>>>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>>>>  #define vgic_initialized(k)	(false)
>>>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>>>> index 8e34916..a95aabc 100644
>>>> --- a/virt/kvm/arm/vgic/vgic.c
>>>> +++ b/virt/kvm/arm/vgic/vgic.c
>>>> @@ -19,8 +19,25 @@
>>>>  
>>>>  #include "vgic.h"
>>>>  
>>>> +#define CREATE_TRACE_POINTS
>>>> +#include "../trace.h"
>>>> +
>>>>  struct vgic_global kvm_vgic_global_state;
>>>>  
>>>> +/*
>>>> + * Locking order is always:
>>>> + *   vgic_cpu->ap_list_lock
>>>> + *     vgic_irq->irq_lock
>>>> + *
>>>> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
>>>> + *
>>>> + * When taking more than one ap_list_lock at the same time, always take the
>>>> + * lowest numbered VCPU's ap_list_lock first, so:
>>>> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
>>>> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
>>>> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
>>>> + */
>>>> +
>>>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>>>  			      u32 intid)
>>>>  {
>>>> @@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>>>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>>>>  	return NULL;
>>>>  }
>>>> +
>>>> +/**
>>>> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
>>>> + *
>>>> + * @irq:	The irq to route. Must be already locked.
>>
>>                                   ^^^^^^^^^^^^^^^^^^^^^^
>>
>>>> + *
>>>> + * Based on the current state of the interrupt (enabled, pending,
>>>> + * active, vcpu and target_vcpu), compute the next vcpu this should be
>>>> + * given to. Return NULL if this shouldn't be injected at all.
>>>> + */
>>>> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
>>>> +{
>>>> +	/* If the interrupt is active, it must stay on the current vcpu */
>>>> +	if (irq->active)
>>>> +		return irq->vcpu;
>>>
>>> we are not taking a lock here.  What are the locking expectations?  If
>>> the expectarions are that the IRQ is locked when calling this function,
>>> can we have a BIG FAT COMMENT saying that then?
>>
>> Do you mean really BIG FAT or is the above sufficient? (I guess not).
>> I will make it more prominent.
> 
> well, maybe it doesn't have to be BIG FAT.  But I did miss the existing
> comment.  I think it would be preferred to have a separate paragraph
> explaining the locking expectaions, but perhaps I'm just
> being stupid.

Fixed - not you being stupid - which you clearly aren't, so nothing to
fix here; but the insufficient comment ;-)

>>
>>> It seems to me that we are somehow expecting irq->active and irq->vcpu
>>> to be in sync, but that's not necessarily the case if the IRQ is not
>>> locked.
>>>
>>>> +
>>>> +	/* If enabled and pending, it can migrate to a new one */
>>>
>>> I think this comment should be rewritten to:
>>>
>>> If the IRQ is not active but enabled and pending, we should direct it to
>>> its configured target VCPU.
>>>
>>>> +	if (irq->enabled && irq->pending)
>>>> +		return irq->target_vcpu;
>>>> +
>>>> +	/* Otherwise, it is considered idle */
>>>
>>> not sure what idle means here, I suggest something like:
>>>
>>> If neither active nor pending and enabled, then this IRQ should not be
>>> queued to any VCPU.
>>>
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Only valid injection if changing level for level-triggered IRQs or for a
>>>> + * rising edge.
>>>> + */
>>>> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
>>>> +{
>>>> +	switch (irq->config) {
>>>> +	case VGIC_CONFIG_LEVEL:
>>>> +		return irq->line_level != level;
>>>> +	case VGIC_CONFIG_EDGE:
>>>> +		return level;
>>>> +	default:
>>>> +		BUG();
>>>
>>> is the default case there for making the compiler happy or can we just
>>> get rid of it?
>>
>> Just removing it was fine (for GCC 5.3.0, at least).
>>
>>>> +	}
>>>> +}
>>>> +
>>>> +/*
>>>> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
>>>> + * Do the queuing if necessary, taking the right locks in the right order.
>>>> + * Returns true when the IRQ was queued, false otherwise.
>>>> + *
>>>> + * Needs to be entered with the IRQ lock already held, but will return
>>>> + * with all locks dropped.
>>>> + */
>>>> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)
>>>
>>> should we name this vgic_try_queue_irq_locked ?
>>
>> Mmh, since it (re-)tries quite hard I am not sure _try_ would be
>> misleading. Basically it queues the IRQ whenever possible and/or
>> sensible. Having _unlock in it like you suggested in another reply makes
>> more sense, I think.
> 
> agreed
> 
>>
>>>> +{
>>>> +	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);
>>>
>>> should we have something like BUG_ON(!spin_is_locked(irq->irq_lock));
>>> here?
>>>
>>> Not sure if there's some bug checking here which is only emitted if a
>>> user select CONFIG_CHECK_SOME_LOCKING_THINGS that we could use...?
>>
>> There is CONFIG_DEBUG_SPINLOCK, but I couldn't find some conditional
>> debug macro suitable for the purpose. I defined one now for the file
>> only (since we have quite some users here).
>>
>>>> +
>>>> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
>>>> +		/*
>>>> +		 * If this IRQ is already on a VCPU's ap_list, then it
>>>> +		 * cannot be moved or modified and there is no more work for
>>>> +		 * us to do.
>>>> +		 *
>>>> +		 * Otherwise, if the irq is not pending and enabled, it does
>>>> +		 * not need to be inserted into an ap_list and there is also
>>>> +		 * no more work for us to do.
>>>> +		 */
>>>
>>> is the !vcpu check here not redundant because if you ever get to
>>> evaluating it, then irq->vcpu is null, and pending and enabled are set,
>>> which means the oracle couldn't have returned null, could it?
>>
>> In this case vcpu is always irq->target_vcpu, if I did the math
>> correctly. So can this be NULL?
>> Even if this is correct reasoning, I wonder if we optimize something
>> prematurely here and rely on the current implementation of
>> vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
>> NULL pointer deference below (in the first spin_lock after the retry:
>> label), so I'd rather keep this explicit check in here.
> 
> I'm really not a fan of building the correctness of one of the most
> crucial parts of our code based on "let's add a few extra checks which
> may not be necessary, just in case" kind of logic.
> 
> So let's be clear on why we have an if-statement here exactly:
> 
> As the comment says, if we can't move the IRQ, because it's already
> assigned to somebody or if this IRQ is not pending or active, then it's
> shouldn't be queued.
> 
> So the simple and all-encompassing check here is simply:
> 
> 	if (irq->vcpu || !vcpu) {
> 		spin_unlock(&irq->irq_lock);
> 		return false;
> 	}
> 
> The only requirement for this to be correct is that the MMIO handler for
> ISACTIVER to both set the active bit and the irq->vcpu pointer (and put
> it on the AP list), without calling this function...).  That was my
> quesiton below.
> 
> Because if that's not the case, you could end up here with irq->active
> set, but irq->vcpu == NULL and !(pending && enabled) and you'd error
> out, which means you would have to check explicitly for the active state
> here as well, but I think that just becomes too messy.
> 
> So, just change this to what I propose and we can deal with the active
> state MMIO handler separately.

I agree that setting the active state via MMIO is a mess in general and
stuffing this case into this function here gets hairy.
I am tempted to not support it in the first version, I guess it never
really worked reliably before ...

At the moment I am trying to code this explicitly into the SACTIVER
handler and it's messy, too (because of the corner cases).
Let's see how this will look like ...

>>
>>> that would also explain why we don't have to re-check the same
>>> conditions below...
>>>
>>> or am I getting this wrong, because you could also have someone
>>> explicitly setting the IRQ to active via trapped MMIO, in which case we
>>> should be able to queue it without it being pending && enabled, which
>>> would indicate that it's the other way around, you should only evaluate
>>> !vcpu and kup the !(pending && enabled) part....?
>>
>> You lost me here, which hints at the fragility of this optimization ;-)
>>
>>>> +		spin_unlock(&irq->irq_lock);
>>>> +		return false;
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * We must unlock the irq lock to take the ap_list_lock where
>>>> +	 * we are going to insert this new pending interrupt.
>>>> +	 */
>>>> +	spin_unlock(&irq->irq_lock);
>>>> +
>>>> +	/* someone can do stuff here, which we re-check below */
>>>> +retry:
>>>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>>>> +	spin_lock(&irq->irq_lock);
>>>> +
>>>> +	/*
>>>> +	 * Did something change behind our backs?
>>>> +	 *
>>>> +	 * There are two cases:
>>>> +	 * 1) The irq became pending or active behind our backs and/or
>>>> +	 *    the irq->vcpu field was set correspondingly when putting
>>>> +	 *    the irq on an ap_list. Then drop the locks and return.
>>>> +	 * 2) Someone changed the affinity on this irq behind our
>>>> +	 *    backs and we are now holding the wrong ap_list_lock.
>>>> +	 *    Then drop the locks and try the new VCPU.
>>>> +	 */
>>>> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
>>>
>>> here I'm concerned about the active state again.
>>
>> Mmmh, can you elaborate and sketch a case where the active state would
>> cause trouble? This check is just here to avoid iterating on a no longer
>> pending or enabled IRQ. I wonder if an active IRQ can really sneak into
>> this function here in the first place?
> 
> After having gone through the series I think we should deal with
> the active state queing directly in the vgic_mmio_write_sactive()
> function.
> 
> But I still prefer to move the retry label to the very top of this
> function, and simplify these two statemtns to the condition I suggested:
> 
> 	if (unlinkely(irq->vcpu || vcpu != vgic_target_oracle(irq)))
> 		goto retry;
> 
> The cost is that we perform a few additional checks at runtime in the
> case where the IRQ was migrated while we released a lock (rare), but I
> think it simplifies the code.

OK, I made this change. Also the shorter check after asking the oracle
above.
This should also better work in the case where target_vcpu is NULL
(because either no bit in TARGETSR is set or a non-existent MPIDR has
been written into IROUTER).

Cheers,
Andre.

>>
>>> I feel like something more similar to my initial version of this patch
>>> is what we really want:
>>>
>>>        if (irq->vcpu || vcpu != vgic_target_oracle(irq))
>>>            goto real_retry;
>>>
>>> and read_retry is then a label at the very top of this function, before
>>> the initial call to vgic_target_oracle()....
>>>
>>>> +		spin_unlock(&irq->irq_lock);
>>>> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>>>> +		return false;
>>>> +	}
>>>> +
>>>> +	if (irq->target_vcpu != vcpu) {
>>>> +		spin_unlock(&irq->irq_lock);
>>>> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>>>> +
>>>> +		vcpu = irq->target_vcpu;
>>>> +		goto retry;
>>>> +	}
>>>> +
>>>> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
>>>> +	irq->vcpu = vcpu;
>>>> +
>>>> +	spin_unlock(&irq->irq_lock);
>>>> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>>>> +
>>>> +	kvm_vcpu_kick(vcpu);
>>>> +
>>>> +	return true;
>>>> +}
>>>> +
>>>> +static void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>>> +				    u32 intid, bool level)
>>>> +{
>>>> +	struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
>>>> +
>>>> +	trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
>>>> +
>>>> +	BUG_ON(in_interrupt());
>>>
>>> I don't remember why we thought it was a good idea to have this BUG_ON()
>>> anymore.  Anyone?
>>
>> Me neither. Is that because of the case where "kvm_notify_acked_irq
>> calls kvm_set_irq" (which in turn may call this function)?
>> I am happy to remove it, also as the old VGIC doesn't seem to have it.
> 
> ok, nuke it.
> 
>>
>>>> +
>>>> +	spin_lock(&irq->irq_lock);
>>>> +
>>>> +	if (!vgic_validate_injection(irq, level)) {
>>>> +		/* Nothing to see here, move along... */
>>>> +		spin_unlock(&irq->irq_lock);
>>>> +		return;
>>>> +	}
>>>> +
>>>> +	if (irq->config == VGIC_CONFIG_LEVEL) {
>>>> +		irq->line_level = level;
>>>> +		irq->pending = level || irq->soft_pending;
>>>> +	} else {
>>>> +		irq->pending = true;
>>>> +	}
>>>> +
>>>> +	vgic_queue_irq(kvm, irq);
>>>> +}
>>>> +
>>>> +/**
>>>> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
>>>> + * @kvm:     The VM structure pointer
>>>> + * @cpuid:   The CPU for PPIs
>>>> + * @intid:   The INTID to inject a new state to.
>>>> + *           must not be mapped to a HW interrupt.
>>>
>>> stray line here?  I don't understand this bit about 'must not be mapped'
>>> and I think that should be moved to the explanation below with some
>>> rationale, and if important, perhaps guarded with a BUG_ON() ?
>>
>> I think this is a copy&paste leftover from the old VGIC with the old way
>> of handling mapped IRQs. Actually the implementations of
>> kvm_vgic_inject_irq() and kvm_vgic_inject_mapped_irq() are now
>> identical, so the former differentiation does not apply anymore. I will
>> #define the latter to the former for the new VGIC and we should schedule
>> the removal of the the "mapped" version when the old VGIC gets removed.
> 
> sounds good.
> 
>>
>> Btw: Are we OK with marking those cases which deserve some rework after
>> the old VGIC is gone with some kind of TODO comments?
>>
> 
> I really think we should avoid merging TODOs as much as possible, but in
> this case it's an exported interface function which could be hard to
> work around with the current vgic, so it may be an exception to the
> rule.
> 
> Thanks,
> -Christoffer
> 

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

* [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-04-14 10:53           ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-14 10:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hej,

On 06/04/16 15:23, Christoffer Dall wrote:
> On Tue, Apr 05, 2016 at 06:28:55PM +0100, Andre Przywara wrote:
>> Hi,
>>
>> On 29/03/16 22:16, Christoffer Dall wrote:
>>> On Fri, Mar 25, 2016 at 02:04:29AM +0000, Andre Przywara wrote:
>>>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>>>
>>>> Provide a vgic_queue_irq() function which decides whether a given
>>>> IRQ needs to be queued to a VCPU's ap_list.
>>>> This should be called whenever an IRQ became pending or got enabled,
>>>
>>> becomes pending or enabled,
>>>
>>>> either as a result of userspace injection, from in-kernel emulated
>>>> devices like the architected timer or from MMIO accesses to the
>>>> distributor emulation.
>>>> Also provides the necessary functions to allow userland to inject an
>>>> IRQ to a guest.
>>>
>>> Since this is the first code that starts using our locking mechanism, we
>>> add some (hopefully) clear documentation of our locking strategy and
>>> requirements along with this patch.
>>>
>>>> [Andre: refactor out vgic_queue_irq()]
>>>>
>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>>  include/kvm/vgic/vgic.h  |   3 +
>>>>  virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.h |   1 +
>>>>  3 files changed, 185 insertions(+)
>>>>
>>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>>>> index 659f8b1..f32b284 100644
>>>> --- a/include/kvm/vgic/vgic.h
>>>> +++ b/include/kvm/vgic/vgic.h
>>>> @@ -178,6 +178,9 @@ struct vgic_cpu {
>>>>  	struct list_head ap_list_head;
>>>>  };
>>>>  
>>>> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>>> +			bool level);
>>>> +
>>>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>>>>  #define vgic_initialized(k)	(false)
>>>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>>>> index 8e34916..a95aabc 100644
>>>> --- a/virt/kvm/arm/vgic/vgic.c
>>>> +++ b/virt/kvm/arm/vgic/vgic.c
>>>> @@ -19,8 +19,25 @@
>>>>  
>>>>  #include "vgic.h"
>>>>  
>>>> +#define CREATE_TRACE_POINTS
>>>> +#include "../trace.h"
>>>> +
>>>>  struct vgic_global kvm_vgic_global_state;
>>>>  
>>>> +/*
>>>> + * Locking order is always:
>>>> + *   vgic_cpu->ap_list_lock
>>>> + *     vgic_irq->irq_lock
>>>> + *
>>>> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
>>>> + *
>>>> + * When taking more than one ap_list_lock at the same time, always take the
>>>> + * lowest numbered VCPU's ap_list_lock first, so:
>>>> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
>>>> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
>>>> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
>>>> + */
>>>> +
>>>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>>>  			      u32 intid)
>>>>  {
>>>> @@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>>>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>>>>  	return NULL;
>>>>  }
>>>> +
>>>> +/**
>>>> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
>>>> + *
>>>> + * @irq:	The irq to route. Must be already locked.
>>
>>                                   ^^^^^^^^^^^^^^^^^^^^^^
>>
>>>> + *
>>>> + * Based on the current state of the interrupt (enabled, pending,
>>>> + * active, vcpu and target_vcpu), compute the next vcpu this should be
>>>> + * given to. Return NULL if this shouldn't be injected at all.
>>>> + */
>>>> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
>>>> +{
>>>> +	/* If the interrupt is active, it must stay on the current vcpu */
>>>> +	if (irq->active)
>>>> +		return irq->vcpu;
>>>
>>> we are not taking a lock here.  What are the locking expectations?  If
>>> the expectarions are that the IRQ is locked when calling this function,
>>> can we have a BIG FAT COMMENT saying that then?
>>
>> Do you mean really BIG FAT or is the above sufficient? (I guess not).
>> I will make it more prominent.
> 
> well, maybe it doesn't have to be BIG FAT.  But I did miss the existing
> comment.  I think it would be preferred to have a separate paragraph
> explaining the locking expectaions, but perhaps I'm just
> being stupid.

Fixed - not you being stupid - which you clearly aren't, so nothing to
fix here; but the insufficient comment ;-)

>>
>>> It seems to me that we are somehow expecting irq->active and irq->vcpu
>>> to be in sync, but that's not necessarily the case if the IRQ is not
>>> locked.
>>>
>>>> +
>>>> +	/* If enabled and pending, it can migrate to a new one */
>>>
>>> I think this comment should be rewritten to:
>>>
>>> If the IRQ is not active but enabled and pending, we should direct it to
>>> its configured target VCPU.
>>>
>>>> +	if (irq->enabled && irq->pending)
>>>> +		return irq->target_vcpu;
>>>> +
>>>> +	/* Otherwise, it is considered idle */
>>>
>>> not sure what idle means here, I suggest something like:
>>>
>>> If neither active nor pending and enabled, then this IRQ should not be
>>> queued to any VCPU.
>>>
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Only valid injection if changing level for level-triggered IRQs or for a
>>>> + * rising edge.
>>>> + */
>>>> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
>>>> +{
>>>> +	switch (irq->config) {
>>>> +	case VGIC_CONFIG_LEVEL:
>>>> +		return irq->line_level != level;
>>>> +	case VGIC_CONFIG_EDGE:
>>>> +		return level;
>>>> +	default:
>>>> +		BUG();
>>>
>>> is the default case there for making the compiler happy or can we just
>>> get rid of it?
>>
>> Just removing it was fine (for GCC 5.3.0, at least).
>>
>>>> +	}
>>>> +}
>>>> +
>>>> +/*
>>>> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
>>>> + * Do the queuing if necessary, taking the right locks in the right order.
>>>> + * Returns true when the IRQ was queued, false otherwise.
>>>> + *
>>>> + * Needs to be entered with the IRQ lock already held, but will return
>>>> + * with all locks dropped.
>>>> + */
>>>> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)
>>>
>>> should we name this vgic_try_queue_irq_locked ?
>>
>> Mmh, since it (re-)tries quite hard I am not sure _try_ would be
>> misleading. Basically it queues the IRQ whenever possible and/or
>> sensible. Having _unlock in it like you suggested in another reply makes
>> more sense, I think.
> 
> agreed
> 
>>
>>>> +{
>>>> +	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);
>>>
>>> should we have something like BUG_ON(!spin_is_locked(irq->irq_lock));
>>> here?
>>>
>>> Not sure if there's some bug checking here which is only emitted if a
>>> user select CONFIG_CHECK_SOME_LOCKING_THINGS that we could use...?
>>
>> There is CONFIG_DEBUG_SPINLOCK, but I couldn't find some conditional
>> debug macro suitable for the purpose. I defined one now for the file
>> only (since we have quite some users here).
>>
>>>> +
>>>> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
>>>> +		/*
>>>> +		 * If this IRQ is already on a VCPU's ap_list, then it
>>>> +		 * cannot be moved or modified and there is no more work for
>>>> +		 * us to do.
>>>> +		 *
>>>> +		 * Otherwise, if the irq is not pending and enabled, it does
>>>> +		 * not need to be inserted into an ap_list and there is also
>>>> +		 * no more work for us to do.
>>>> +		 */
>>>
>>> is the !vcpu check here not redundant because if you ever get to
>>> evaluating it, then irq->vcpu is null, and pending and enabled are set,
>>> which means the oracle couldn't have returned null, could it?
>>
>> In this case vcpu is always irq->target_vcpu, if I did the math
>> correctly. So can this be NULL?
>> Even if this is correct reasoning, I wonder if we optimize something
>> prematurely here and rely on the current implementation of
>> vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
>> NULL pointer deference below (in the first spin_lock after the retry:
>> label), so I'd rather keep this explicit check in here.
> 
> I'm really not a fan of building the correctness of one of the most
> crucial parts of our code based on "let's add a few extra checks which
> may not be necessary, just in case" kind of logic.
> 
> So let's be clear on why we have an if-statement here exactly:
> 
> As the comment says, if we can't move the IRQ, because it's already
> assigned to somebody or if this IRQ is not pending or active, then it's
> shouldn't be queued.
> 
> So the simple and all-encompassing check here is simply:
> 
> 	if (irq->vcpu || !vcpu) {
> 		spin_unlock(&irq->irq_lock);
> 		return false;
> 	}
> 
> The only requirement for this to be correct is that the MMIO handler for
> ISACTIVER to both set the active bit and the irq->vcpu pointer (and put
> it on the AP list), without calling this function...).  That was my
> quesiton below.
> 
> Because if that's not the case, you could end up here with irq->active
> set, but irq->vcpu == NULL and !(pending && enabled) and you'd error
> out, which means you would have to check explicitly for the active state
> here as well, but I think that just becomes too messy.
> 
> So, just change this to what I propose and we can deal with the active
> state MMIO handler separately.

I agree that setting the active state via MMIO is a mess in general and
stuffing this case into this function here gets hairy.
I am tempted to not support it in the first version, I guess it never
really worked reliably before ...

At the moment I am trying to code this explicitly into the SACTIVER
handler and it's messy, too (because of the corner cases).
Let's see how this will look like ...

>>
>>> that would also explain why we don't have to re-check the same
>>> conditions below...
>>>
>>> or am I getting this wrong, because you could also have someone
>>> explicitly setting the IRQ to active via trapped MMIO, in which case we
>>> should be able to queue it without it being pending && enabled, which
>>> would indicate that it's the other way around, you should only evaluate
>>> !vcpu and kup the !(pending && enabled) part....?
>>
>> You lost me here, which hints at the fragility of this optimization ;-)
>>
>>>> +		spin_unlock(&irq->irq_lock);
>>>> +		return false;
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * We must unlock the irq lock to take the ap_list_lock where
>>>> +	 * we are going to insert this new pending interrupt.
>>>> +	 */
>>>> +	spin_unlock(&irq->irq_lock);
>>>> +
>>>> +	/* someone can do stuff here, which we re-check below */
>>>> +retry:
>>>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>>>> +	spin_lock(&irq->irq_lock);
>>>> +
>>>> +	/*
>>>> +	 * Did something change behind our backs?
>>>> +	 *
>>>> +	 * There are two cases:
>>>> +	 * 1) The irq became pending or active behind our backs and/or
>>>> +	 *    the irq->vcpu field was set correspondingly when putting
>>>> +	 *    the irq on an ap_list. Then drop the locks and return.
>>>> +	 * 2) Someone changed the affinity on this irq behind our
>>>> +	 *    backs and we are now holding the wrong ap_list_lock.
>>>> +	 *    Then drop the locks and try the new VCPU.
>>>> +	 */
>>>> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
>>>
>>> here I'm concerned about the active state again.
>>
>> Mmmh, can you elaborate and sketch a case where the active state would
>> cause trouble? This check is just here to avoid iterating on a no longer
>> pending or enabled IRQ. I wonder if an active IRQ can really sneak into
>> this function here in the first place?
> 
> After having gone through the series I think we should deal with
> the active state queing directly in the vgic_mmio_write_sactive()
> function.
> 
> But I still prefer to move the retry label to the very top of this
> function, and simplify these two statemtns to the condition I suggested:
> 
> 	if (unlinkely(irq->vcpu || vcpu != vgic_target_oracle(irq)))
> 		goto retry;
> 
> The cost is that we perform a few additional checks at runtime in the
> case where the IRQ was migrated while we released a lock (rare), but I
> think it simplifies the code.

OK, I made this change. Also the shorter check after asking the oracle
above.
This should also better work in the case where target_vcpu is NULL
(because either no bit in TARGETSR is set or a non-existent MPIDR has
been written into IROUTER).

Cheers,
Andre.

>>
>>> I feel like something more similar to my initial version of this patch
>>> is what we really want:
>>>
>>>        if (irq->vcpu || vcpu != vgic_target_oracle(irq))
>>>            goto real_retry;
>>>
>>> and read_retry is then a label at the very top of this function, before
>>> the initial call to vgic_target_oracle()....
>>>
>>>> +		spin_unlock(&irq->irq_lock);
>>>> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>>>> +		return false;
>>>> +	}
>>>> +
>>>> +	if (irq->target_vcpu != vcpu) {
>>>> +		spin_unlock(&irq->irq_lock);
>>>> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>>>> +
>>>> +		vcpu = irq->target_vcpu;
>>>> +		goto retry;
>>>> +	}
>>>> +
>>>> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
>>>> +	irq->vcpu = vcpu;
>>>> +
>>>> +	spin_unlock(&irq->irq_lock);
>>>> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>>>> +
>>>> +	kvm_vcpu_kick(vcpu);
>>>> +
>>>> +	return true;
>>>> +}
>>>> +
>>>> +static void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>>> +				    u32 intid, bool level)
>>>> +{
>>>> +	struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
>>>> +
>>>> +	trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
>>>> +
>>>> +	BUG_ON(in_interrupt());
>>>
>>> I don't remember why we thought it was a good idea to have this BUG_ON()
>>> anymore.  Anyone?
>>
>> Me neither. Is that because of the case where "kvm_notify_acked_irq
>> calls kvm_set_irq" (which in turn may call this function)?
>> I am happy to remove it, also as the old VGIC doesn't seem to have it.
> 
> ok, nuke it.
> 
>>
>>>> +
>>>> +	spin_lock(&irq->irq_lock);
>>>> +
>>>> +	if (!vgic_validate_injection(irq, level)) {
>>>> +		/* Nothing to see here, move along... */
>>>> +		spin_unlock(&irq->irq_lock);
>>>> +		return;
>>>> +	}
>>>> +
>>>> +	if (irq->config == VGIC_CONFIG_LEVEL) {
>>>> +		irq->line_level = level;
>>>> +		irq->pending = level || irq->soft_pending;
>>>> +	} else {
>>>> +		irq->pending = true;
>>>> +	}
>>>> +
>>>> +	vgic_queue_irq(kvm, irq);
>>>> +}
>>>> +
>>>> +/**
>>>> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
>>>> + * @kvm:     The VM structure pointer
>>>> + * @cpuid:   The CPU for PPIs
>>>> + * @intid:   The INTID to inject a new state to.
>>>> + *           must not be mapped to a HW interrupt.
>>>
>>> stray line here?  I don't understand this bit about 'must not be mapped'
>>> and I think that should be moved to the explanation below with some
>>> rationale, and if important, perhaps guarded with a BUG_ON() ?
>>
>> I think this is a copy&paste leftover from the old VGIC with the old way
>> of handling mapped IRQs. Actually the implementations of
>> kvm_vgic_inject_irq() and kvm_vgic_inject_mapped_irq() are now
>> identical, so the former differentiation does not apply anymore. I will
>> #define the latter to the former for the new VGIC and we should schedule
>> the removal of the the "mapped" version when the old VGIC gets removed.
> 
> sounds good.
> 
>>
>> Btw: Are we OK with marking those cases which deserve some rework after
>> the old VGIC is gone with some kind of TODO comments?
>>
> 
> I really think we should avoid merging TODOs as much as possible, but in
> this case it's an exported interface function which could be hard to
> work around with the current vgic, so it may be an exception to the
> rule.
> 
> Thanks,
> -Christoffer
> 

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

* Re: [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-04-14 10:53           ` Andre Przywara
@ 2016-04-14 12:15             ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-14 12:15 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Thu, Apr 14, 2016 at 11:53:14AM +0100, Andre Przywara wrote:
> Hej,
> 
> On 06/04/16 15:23, Christoffer Dall wrote:
> > On Tue, Apr 05, 2016 at 06:28:55PM +0100, Andre Przywara wrote:
> >> Hi,
> >>
> >> On 29/03/16 22:16, Christoffer Dall wrote:
> >>> On Fri, Mar 25, 2016 at 02:04:29AM +0000, Andre Przywara wrote:
> >>>> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>>>
> >>>> Provide a vgic_queue_irq() function which decides whether a given
> >>>> IRQ needs to be queued to a VCPU's ap_list.
> >>>> This should be called whenever an IRQ became pending or got enabled,
> >>>
> >>> becomes pending or enabled,
> >>>
> >>>> either as a result of userspace injection, from in-kernel emulated
> >>>> devices like the architected timer or from MMIO accesses to the
> >>>> distributor emulation.
> >>>> Also provides the necessary functions to allow userland to inject an
> >>>> IRQ to a guest.
> >>>
> >>> Since this is the first code that starts using our locking mechanism, we
> >>> add some (hopefully) clear documentation of our locking strategy and
> >>> requirements along with this patch.
> >>>
> >>>> [Andre: refactor out vgic_queue_irq()]
> >>>>
> >>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> ---
> >>>>  include/kvm/vgic/vgic.h  |   3 +
> >>>>  virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic.h |   1 +
> >>>>  3 files changed, 185 insertions(+)
> >>>>
> >>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >>>> index 659f8b1..f32b284 100644
> >>>> --- a/include/kvm/vgic/vgic.h
> >>>> +++ b/include/kvm/vgic/vgic.h
> >>>> @@ -178,6 +178,9 @@ struct vgic_cpu {
> >>>>  	struct list_head ap_list_head;
> >>>>  };
> >>>>  
> >>>> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> >>>> +			bool level);
> >>>> +
> >>>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> >>>>  #define vgic_initialized(k)	(false)
> >>>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> >>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> >>>> index 8e34916..a95aabc 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic.c
> >>>> @@ -19,8 +19,25 @@
> >>>>  
> >>>>  #include "vgic.h"
> >>>>  
> >>>> +#define CREATE_TRACE_POINTS
> >>>> +#include "../trace.h"
> >>>> +
> >>>>  struct vgic_global kvm_vgic_global_state;
> >>>>  
> >>>> +/*
> >>>> + * Locking order is always:
> >>>> + *   vgic_cpu->ap_list_lock
> >>>> + *     vgic_irq->irq_lock
> >>>> + *
> >>>> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
> >>>> + *
> >>>> + * When taking more than one ap_list_lock at the same time, always take the
> >>>> + * lowest numbered VCPU's ap_list_lock first, so:
> >>>> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
> >>>> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
> >>>> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
> >>>> + */
> >>>> +
> >>>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>>>  			      u32 intid)
> >>>>  {
> >>>> @@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>>>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
> >>>>  	return NULL;
> >>>>  }
> >>>> +
> >>>> +/**
> >>>> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
> >>>> + *
> >>>> + * @irq:	The irq to route. Must be already locked.
> >>
> >>                                   ^^^^^^^^^^^^^^^^^^^^^^
> >>
> >>>> + *
> >>>> + * Based on the current state of the interrupt (enabled, pending,
> >>>> + * active, vcpu and target_vcpu), compute the next vcpu this should be
> >>>> + * given to. Return NULL if this shouldn't be injected at all.
> >>>> + */
> >>>> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
> >>>> +{
> >>>> +	/* If the interrupt is active, it must stay on the current vcpu */
> >>>> +	if (irq->active)
> >>>> +		return irq->vcpu;
> >>>
> >>> we are not taking a lock here.  What are the locking expectations?  If
> >>> the expectarions are that the IRQ is locked when calling this function,
> >>> can we have a BIG FAT COMMENT saying that then?
> >>
> >> Do you mean really BIG FAT or is the above sufficient? (I guess not).
> >> I will make it more prominent.
> > 
> > well, maybe it doesn't have to be BIG FAT.  But I did miss the existing
> > comment.  I think it would be preferred to have a separate paragraph
> > explaining the locking expectaions, but perhaps I'm just
> > being stupid.
> 
> Fixed - not you being stupid - which you clearly aren't, so nothing to
> fix here; but the insufficient comment ;-)
> 
> >>
> >>> It seems to me that we are somehow expecting irq->active and irq->vcpu
> >>> to be in sync, but that's not necessarily the case if the IRQ is not
> >>> locked.
> >>>
> >>>> +
> >>>> +	/* If enabled and pending, it can migrate to a new one */
> >>>
> >>> I think this comment should be rewritten to:
> >>>
> >>> If the IRQ is not active but enabled and pending, we should direct it to
> >>> its configured target VCPU.
> >>>
> >>>> +	if (irq->enabled && irq->pending)
> >>>> +		return irq->target_vcpu;
> >>>> +
> >>>> +	/* Otherwise, it is considered idle */
> >>>
> >>> not sure what idle means here, I suggest something like:
> >>>
> >>> If neither active nor pending and enabled, then this IRQ should not be
> >>> queued to any VCPU.
> >>>
> >>>> +	return NULL;
> >>>> +}
> >>>> +
> >>>> +/*
> >>>> + * Only valid injection if changing level for level-triggered IRQs or for a
> >>>> + * rising edge.
> >>>> + */
> >>>> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
> >>>> +{
> >>>> +	switch (irq->config) {
> >>>> +	case VGIC_CONFIG_LEVEL:
> >>>> +		return irq->line_level != level;
> >>>> +	case VGIC_CONFIG_EDGE:
> >>>> +		return level;
> >>>> +	default:
> >>>> +		BUG();
> >>>
> >>> is the default case there for making the compiler happy or can we just
> >>> get rid of it?
> >>
> >> Just removing it was fine (for GCC 5.3.0, at least).
> >>
> >>>> +	}
> >>>> +}
> >>>> +
> >>>> +/*
> >>>> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
> >>>> + * Do the queuing if necessary, taking the right locks in the right order.
> >>>> + * Returns true when the IRQ was queued, false otherwise.
> >>>> + *
> >>>> + * Needs to be entered with the IRQ lock already held, but will return
> >>>> + * with all locks dropped.
> >>>> + */
> >>>> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)
> >>>
> >>> should we name this vgic_try_queue_irq_locked ?
> >>
> >> Mmh, since it (re-)tries quite hard I am not sure _try_ would be
> >> misleading. Basically it queues the IRQ whenever possible and/or
> >> sensible. Having _unlock in it like you suggested in another reply makes
> >> more sense, I think.
> > 
> > agreed
> > 
> >>
> >>>> +{
> >>>> +	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);
> >>>
> >>> should we have something like BUG_ON(!spin_is_locked(irq->irq_lock));
> >>> here?
> >>>
> >>> Not sure if there's some bug checking here which is only emitted if a
> >>> user select CONFIG_CHECK_SOME_LOCKING_THINGS that we could use...?
> >>
> >> There is CONFIG_DEBUG_SPINLOCK, but I couldn't find some conditional
> >> debug macro suitable for the purpose. I defined one now for the file
> >> only (since we have quite some users here).
> >>
> >>>> +
> >>>> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
> >>>> +		/*
> >>>> +		 * If this IRQ is already on a VCPU's ap_list, then it
> >>>> +		 * cannot be moved or modified and there is no more work for
> >>>> +		 * us to do.
> >>>> +		 *
> >>>> +		 * Otherwise, if the irq is not pending and enabled, it does
> >>>> +		 * not need to be inserted into an ap_list and there is also
> >>>> +		 * no more work for us to do.
> >>>> +		 */
> >>>
> >>> is the !vcpu check here not redundant because if you ever get to
> >>> evaluating it, then irq->vcpu is null, and pending and enabled are set,
> >>> which means the oracle couldn't have returned null, could it?
> >>
> >> In this case vcpu is always irq->target_vcpu, if I did the math
> >> correctly. So can this be NULL?
> >> Even if this is correct reasoning, I wonder if we optimize something
> >> prematurely here and rely on the current implementation of
> >> vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
> >> NULL pointer deference below (in the first spin_lock after the retry:
> >> label), so I'd rather keep this explicit check in here.
> > 
> > I'm really not a fan of building the correctness of one of the most
> > crucial parts of our code based on "let's add a few extra checks which
> > may not be necessary, just in case" kind of logic.
> > 
> > So let's be clear on why we have an if-statement here exactly:
> > 
> > As the comment says, if we can't move the IRQ, because it's already
> > assigned to somebody or if this IRQ is not pending or active, then it's
> > shouldn't be queued.
> > 
> > So the simple and all-encompassing check here is simply:
> > 
> > 	if (irq->vcpu || !vcpu) {
> > 		spin_unlock(&irq->irq_lock);
> > 		return false;
> > 	}
> > 
> > The only requirement for this to be correct is that the MMIO handler for
> > ISACTIVER to both set the active bit and the irq->vcpu pointer (and put
> > it on the AP list), without calling this function...).  That was my
> > quesiton below.
> > 
> > Because if that's not the case, you could end up here with irq->active
> > set, but irq->vcpu == NULL and !(pending && enabled) and you'd error
> > out, which means you would have to check explicitly for the active state
> > here as well, but I think that just becomes too messy.
> > 
> > So, just change this to what I propose and we can deal with the active
> > state MMIO handler separately.
> 
> I agree that setting the active state via MMIO is a mess in general and
> stuffing this case into this function here gets hairy.
> I am tempted to not support it in the first version, I guess it never
> really worked reliably before ...

I'm pretty sure it did, because we ran into migration breaking when this
wasn't supported for the save/restore userspace interface.

> 
> At the moment I am trying to code this explicitly into the SACTIVER
> handler and it's messy, too (because of the corner cases).
> Let's see how this will look like ...

ok.

If you want, you can focus on getting a new version out, and I can take
a stab at the SACTIVER together with the priority stuff.  OTOH, if you
already have something, then it may be worth following through with
that.

> 
> >>
> >>> that would also explain why we don't have to re-check the same
> >>> conditions below...
> >>>
> >>> or am I getting this wrong, because you could also have someone
> >>> explicitly setting the IRQ to active via trapped MMIO, in which case we
> >>> should be able to queue it without it being pending && enabled, which
> >>> would indicate that it's the other way around, you should only evaluate
> >>> !vcpu and kup the !(pending && enabled) part....?
> >>
> >> You lost me here, which hints at the fragility of this optimization ;-)
> >>
> >>>> +		spin_unlock(&irq->irq_lock);
> >>>> +		return false;
> >>>> +	}
> >>>> +
> >>>> +	/*
> >>>> +	 * We must unlock the irq lock to take the ap_list_lock where
> >>>> +	 * we are going to insert this new pending interrupt.
> >>>> +	 */
> >>>> +	spin_unlock(&irq->irq_lock);
> >>>> +
> >>>> +	/* someone can do stuff here, which we re-check below */
> >>>> +retry:
> >>>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >>>> +	spin_lock(&irq->irq_lock);
> >>>> +
> >>>> +	/*
> >>>> +	 * Did something change behind our backs?
> >>>> +	 *
> >>>> +	 * There are two cases:
> >>>> +	 * 1) The irq became pending or active behind our backs and/or
> >>>> +	 *    the irq->vcpu field was set correspondingly when putting
> >>>> +	 *    the irq on an ap_list. Then drop the locks and return.
> >>>> +	 * 2) Someone changed the affinity on this irq behind our
> >>>> +	 *    backs and we are now holding the wrong ap_list_lock.
> >>>> +	 *    Then drop the locks and try the new VCPU.
> >>>> +	 */
> >>>> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
> >>>
> >>> here I'm concerned about the active state again.
> >>
> >> Mmmh, can you elaborate and sketch a case where the active state would
> >> cause trouble? This check is just here to avoid iterating on a no longer
> >> pending or enabled IRQ. I wonder if an active IRQ can really sneak into
> >> this function here in the first place?
> > 
> > After having gone through the series I think we should deal with
> > the active state queing directly in the vgic_mmio_write_sactive()
> > function.
> > 
> > But I still prefer to move the retry label to the very top of this
> > function, and simplify these two statemtns to the condition I suggested:
> > 
> > 	if (unlinkely(irq->vcpu || vcpu != vgic_target_oracle(irq)))
> > 		goto retry;
> > 
> > The cost is that we perform a few additional checks at runtime in the
> > case where the IRQ was migrated while we released a lock (rare), but I
> > think it simplifies the code.
> 
> OK, I made this change. Also the shorter check after asking the oracle
> above.
> This should also better work in the case where target_vcpu is NULL
> (because either no bit in TARGETSR is set or a non-existent MPIDR has
> been written into IROUTER).
> 
right.

Thanks,
-Christoffer

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

* [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-04-14 12:15             ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-14 12:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Apr 14, 2016 at 11:53:14AM +0100, Andre Przywara wrote:
> Hej,
> 
> On 06/04/16 15:23, Christoffer Dall wrote:
> > On Tue, Apr 05, 2016 at 06:28:55PM +0100, Andre Przywara wrote:
> >> Hi,
> >>
> >> On 29/03/16 22:16, Christoffer Dall wrote:
> >>> On Fri, Mar 25, 2016 at 02:04:29AM +0000, Andre Przywara wrote:
> >>>> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>>>
> >>>> Provide a vgic_queue_irq() function which decides whether a given
> >>>> IRQ needs to be queued to a VCPU's ap_list.
> >>>> This should be called whenever an IRQ became pending or got enabled,
> >>>
> >>> becomes pending or enabled,
> >>>
> >>>> either as a result of userspace injection, from in-kernel emulated
> >>>> devices like the architected timer or from MMIO accesses to the
> >>>> distributor emulation.
> >>>> Also provides the necessary functions to allow userland to inject an
> >>>> IRQ to a guest.
> >>>
> >>> Since this is the first code that starts using our locking mechanism, we
> >>> add some (hopefully) clear documentation of our locking strategy and
> >>> requirements along with this patch.
> >>>
> >>>> [Andre: refactor out vgic_queue_irq()]
> >>>>
> >>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> ---
> >>>>  include/kvm/vgic/vgic.h  |   3 +
> >>>>  virt/kvm/arm/vgic/vgic.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic.h |   1 +
> >>>>  3 files changed, 185 insertions(+)
> >>>>
> >>>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >>>> index 659f8b1..f32b284 100644
> >>>> --- a/include/kvm/vgic/vgic.h
> >>>> +++ b/include/kvm/vgic/vgic.h
> >>>> @@ -178,6 +178,9 @@ struct vgic_cpu {
> >>>>  	struct list_head ap_list_head;
> >>>>  };
> >>>>  
> >>>> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> >>>> +			bool level);
> >>>> +
> >>>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> >>>>  #define vgic_initialized(k)	(false)
> >>>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> >>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> >>>> index 8e34916..a95aabc 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic.c
> >>>> @@ -19,8 +19,25 @@
> >>>>  
> >>>>  #include "vgic.h"
> >>>>  
> >>>> +#define CREATE_TRACE_POINTS
> >>>> +#include "../trace.h"
> >>>> +
> >>>>  struct vgic_global kvm_vgic_global_state;
> >>>>  
> >>>> +/*
> >>>> + * Locking order is always:
> >>>> + *   vgic_cpu->ap_list_lock
> >>>> + *     vgic_irq->irq_lock
> >>>> + *
> >>>> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
> >>>> + *
> >>>> + * When taking more than one ap_list_lock at the same time, always take the
> >>>> + * lowest numbered VCPU's ap_list_lock first, so:
> >>>> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
> >>>> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
> >>>> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
> >>>> + */
> >>>> +
> >>>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>>>  			      u32 intid)
> >>>>  {
> >>>> @@ -39,3 +56,167 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >>>>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
> >>>>  	return NULL;
> >>>>  }
> >>>> +
> >>>> +/**
> >>>> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
> >>>> + *
> >>>> + * @irq:	The irq to route. Must be already locked.
> >>
> >>                                   ^^^^^^^^^^^^^^^^^^^^^^
> >>
> >>>> + *
> >>>> + * Based on the current state of the interrupt (enabled, pending,
> >>>> + * active, vcpu and target_vcpu), compute the next vcpu this should be
> >>>> + * given to. Return NULL if this shouldn't be injected at all.
> >>>> + */
> >>>> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
> >>>> +{
> >>>> +	/* If the interrupt is active, it must stay on the current vcpu */
> >>>> +	if (irq->active)
> >>>> +		return irq->vcpu;
> >>>
> >>> we are not taking a lock here.  What are the locking expectations?  If
> >>> the expectarions are that the IRQ is locked when calling this function,
> >>> can we have a BIG FAT COMMENT saying that then?
> >>
> >> Do you mean really BIG FAT or is the above sufficient? (I guess not).
> >> I will make it more prominent.
> > 
> > well, maybe it doesn't have to be BIG FAT.  But I did miss the existing
> > comment.  I think it would be preferred to have a separate paragraph
> > explaining the locking expectaions, but perhaps I'm just
> > being stupid.
> 
> Fixed - not you being stupid - which you clearly aren't, so nothing to
> fix here; but the insufficient comment ;-)
> 
> >>
> >>> It seems to me that we are somehow expecting irq->active and irq->vcpu
> >>> to be in sync, but that's not necessarily the case if the IRQ is not
> >>> locked.
> >>>
> >>>> +
> >>>> +	/* If enabled and pending, it can migrate to a new one */
> >>>
> >>> I think this comment should be rewritten to:
> >>>
> >>> If the IRQ is not active but enabled and pending, we should direct it to
> >>> its configured target VCPU.
> >>>
> >>>> +	if (irq->enabled && irq->pending)
> >>>> +		return irq->target_vcpu;
> >>>> +
> >>>> +	/* Otherwise, it is considered idle */
> >>>
> >>> not sure what idle means here, I suggest something like:
> >>>
> >>> If neither active nor pending and enabled, then this IRQ should not be
> >>> queued to any VCPU.
> >>>
> >>>> +	return NULL;
> >>>> +}
> >>>> +
> >>>> +/*
> >>>> + * Only valid injection if changing level for level-triggered IRQs or for a
> >>>> + * rising edge.
> >>>> + */
> >>>> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
> >>>> +{
> >>>> +	switch (irq->config) {
> >>>> +	case VGIC_CONFIG_LEVEL:
> >>>> +		return irq->line_level != level;
> >>>> +	case VGIC_CONFIG_EDGE:
> >>>> +		return level;
> >>>> +	default:
> >>>> +		BUG();
> >>>
> >>> is the default case there for making the compiler happy or can we just
> >>> get rid of it?
> >>
> >> Just removing it was fine (for GCC 5.3.0, at least).
> >>
> >>>> +	}
> >>>> +}
> >>>> +
> >>>> +/*
> >>>> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
> >>>> + * Do the queuing if necessary, taking the right locks in the right order.
> >>>> + * Returns true when the IRQ was queued, false otherwise.
> >>>> + *
> >>>> + * Needs to be entered with the IRQ lock already held, but will return
> >>>> + * with all locks dropped.
> >>>> + */
> >>>> +bool vgic_queue_irq(struct kvm *kvm, struct vgic_irq *irq)
> >>>
> >>> should we name this vgic_try_queue_irq_locked ?
> >>
> >> Mmh, since it (re-)tries quite hard I am not sure _try_ would be
> >> misleading. Basically it queues the IRQ whenever possible and/or
> >> sensible. Having _unlock in it like you suggested in another reply makes
> >> more sense, I think.
> > 
> > agreed
> > 
> >>
> >>>> +{
> >>>> +	struct kvm_vcpu *vcpu = vgic_target_oracle(irq);
> >>>
> >>> should we have something like BUG_ON(!spin_is_locked(irq->irq_lock));
> >>> here?
> >>>
> >>> Not sure if there's some bug checking here which is only emitted if a
> >>> user select CONFIG_CHECK_SOME_LOCKING_THINGS that we could use...?
> >>
> >> There is CONFIG_DEBUG_SPINLOCK, but I couldn't find some conditional
> >> debug macro suitable for the purpose. I defined one now for the file
> >> only (since we have quite some users here).
> >>
> >>>> +
> >>>> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
> >>>> +		/*
> >>>> +		 * If this IRQ is already on a VCPU's ap_list, then it
> >>>> +		 * cannot be moved or modified and there is no more work for
> >>>> +		 * us to do.
> >>>> +		 *
> >>>> +		 * Otherwise, if the irq is not pending and enabled, it does
> >>>> +		 * not need to be inserted into an ap_list and there is also
> >>>> +		 * no more work for us to do.
> >>>> +		 */
> >>>
> >>> is the !vcpu check here not redundant because if you ever get to
> >>> evaluating it, then irq->vcpu is null, and pending and enabled are set,
> >>> which means the oracle couldn't have returned null, could it?
> >>
> >> In this case vcpu is always irq->target_vcpu, if I did the math
> >> correctly. So can this be NULL?
> >> Even if this is correct reasoning, I wonder if we optimize something
> >> prematurely here and rely on the current implementation of
> >> vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
> >> NULL pointer deference below (in the first spin_lock after the retry:
> >> label), so I'd rather keep this explicit check in here.
> > 
> > I'm really not a fan of building the correctness of one of the most
> > crucial parts of our code based on "let's add a few extra checks which
> > may not be necessary, just in case" kind of logic.
> > 
> > So let's be clear on why we have an if-statement here exactly:
> > 
> > As the comment says, if we can't move the IRQ, because it's already
> > assigned to somebody or if this IRQ is not pending or active, then it's
> > shouldn't be queued.
> > 
> > So the simple and all-encompassing check here is simply:
> > 
> > 	if (irq->vcpu || !vcpu) {
> > 		spin_unlock(&irq->irq_lock);
> > 		return false;
> > 	}
> > 
> > The only requirement for this to be correct is that the MMIO handler for
> > ISACTIVER to both set the active bit and the irq->vcpu pointer (and put
> > it on the AP list), without calling this function...).  That was my
> > quesiton below.
> > 
> > Because if that's not the case, you could end up here with irq->active
> > set, but irq->vcpu == NULL and !(pending && enabled) and you'd error
> > out, which means you would have to check explicitly for the active state
> > here as well, but I think that just becomes too messy.
> > 
> > So, just change this to what I propose and we can deal with the active
> > state MMIO handler separately.
> 
> I agree that setting the active state via MMIO is a mess in general and
> stuffing this case into this function here gets hairy.
> I am tempted to not support it in the first version, I guess it never
> really worked reliably before ...

I'm pretty sure it did, because we ran into migration breaking when this
wasn't supported for the save/restore userspace interface.

> 
> At the moment I am trying to code this explicitly into the SACTIVER
> handler and it's messy, too (because of the corner cases).
> Let's see how this will look like ...

ok.

If you want, you can focus on getting a new version out, and I can take
a stab at the SACTIVER together with the priority stuff.  OTOH, if you
already have something, then it may be worth following through with
that.

> 
> >>
> >>> that would also explain why we don't have to re-check the same
> >>> conditions below...
> >>>
> >>> or am I getting this wrong, because you could also have someone
> >>> explicitly setting the IRQ to active via trapped MMIO, in which case we
> >>> should be able to queue it without it being pending && enabled, which
> >>> would indicate that it's the other way around, you should only evaluate
> >>> !vcpu and kup the !(pending && enabled) part....?
> >>
> >> You lost me here, which hints at the fragility of this optimization ;-)
> >>
> >>>> +		spin_unlock(&irq->irq_lock);
> >>>> +		return false;
> >>>> +	}
> >>>> +
> >>>> +	/*
> >>>> +	 * We must unlock the irq lock to take the ap_list_lock where
> >>>> +	 * we are going to insert this new pending interrupt.
> >>>> +	 */
> >>>> +	spin_unlock(&irq->irq_lock);
> >>>> +
> >>>> +	/* someone can do stuff here, which we re-check below */
> >>>> +retry:
> >>>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >>>> +	spin_lock(&irq->irq_lock);
> >>>> +
> >>>> +	/*
> >>>> +	 * Did something change behind our backs?
> >>>> +	 *
> >>>> +	 * There are two cases:
> >>>> +	 * 1) The irq became pending or active behind our backs and/or
> >>>> +	 *    the irq->vcpu field was set correspondingly when putting
> >>>> +	 *    the irq on an ap_list. Then drop the locks and return.
> >>>> +	 * 2) Someone changed the affinity on this irq behind our
> >>>> +	 *    backs and we are now holding the wrong ap_list_lock.
> >>>> +	 *    Then drop the locks and try the new VCPU.
> >>>> +	 */
> >>>> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
> >>>
> >>> here I'm concerned about the active state again.
> >>
> >> Mmmh, can you elaborate and sketch a case where the active state would
> >> cause trouble? This check is just here to avoid iterating on a no longer
> >> pending or enabled IRQ. I wonder if an active IRQ can really sneak into
> >> this function here in the first place?
> > 
> > After having gone through the series I think we should deal with
> > the active state queing directly in the vgic_mmio_write_sactive()
> > function.
> > 
> > But I still prefer to move the retry label to the very top of this
> > function, and simplify these two statemtns to the condition I suggested:
> > 
> > 	if (unlinkely(irq->vcpu || vcpu != vgic_target_oracle(irq)))
> > 		goto retry;
> > 
> > The cost is that we perform a few additional checks at runtime in the
> > case where the IRQ was migrated while we released a lock (rare), but I
> > think it simplifies the code.
> 
> OK, I made this change. Also the shorter check after asking the oracle
> above.
> This should also better work in the case where target_vcpu is NULL
> (because either no bit in TARGETSR is set or a non-existent MPIDR has
> been written into IROUTER).
> 
right.

Thanks,
-Christoffer

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

* Re: [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-04-14 12:15             ` Christoffer Dall
@ 2016-04-14 13:45               ` Andre Przywara
  -1 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-14 13:45 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

....

>>>>>> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
>>>>>> +		/*
>>>>>> +		 * If this IRQ is already on a VCPU's ap_list, then it
>>>>>> +		 * cannot be moved or modified and there is no more work for
>>>>>> +		 * us to do.
>>>>>> +		 *
>>>>>> +		 * Otherwise, if the irq is not pending and enabled, it does
>>>>>> +		 * not need to be inserted into an ap_list and there is also
>>>>>> +		 * no more work for us to do.
>>>>>> +		 */
>>>>>
>>>>> is the !vcpu check here not redundant because if you ever get to
>>>>> evaluating it, then irq->vcpu is null, and pending and enabled are set,
>>>>> which means the oracle couldn't have returned null, could it?
>>>>
>>>> In this case vcpu is always irq->target_vcpu, if I did the math
>>>> correctly. So can this be NULL?
>>>> Even if this is correct reasoning, I wonder if we optimize something
>>>> prematurely here and rely on the current implementation of
>>>> vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
>>>> NULL pointer deference below (in the first spin_lock after the retry:
>>>> label), so I'd rather keep this explicit check in here.
>>>
>>> I'm really not a fan of building the correctness of one of the most
>>> crucial parts of our code based on "let's add a few extra checks which
>>> may not be necessary, just in case" kind of logic.
>>>
>>> So let's be clear on why we have an if-statement here exactly:
>>>
>>> As the comment says, if we can't move the IRQ, because it's already
>>> assigned to somebody or if this IRQ is not pending or active, then it's
>>> shouldn't be queued.
>>>
>>> So the simple and all-encompassing check here is simply:
>>>
>>> 	if (irq->vcpu || !vcpu) {
>>> 		spin_unlock(&irq->irq_lock);
>>> 		return false;
>>> 	}
>>>
>>> The only requirement for this to be correct is that the MMIO handler for
>>> ISACTIVER to both set the active bit and the irq->vcpu pointer (and put
>>> it on the AP list), without calling this function...).  That was my
>>> quesiton below.
>>>
>>> Because if that's not the case, you could end up here with irq->active
>>> set, but irq->vcpu == NULL and !(pending && enabled) and you'd error
>>> out, which means you would have to check explicitly for the active state
>>> here as well, but I think that just becomes too messy.
>>>
>>> So, just change this to what I propose and we can deal with the active
>>> state MMIO handler separately.
>>
>> I agree that setting the active state via MMIO is a mess in general and
>> stuffing this case into this function here gets hairy.
>> I am tempted to not support it in the first version, I guess it never
>> really worked reliably before ...
> 
> I'm pretty sure it did, because we ran into migration breaking when this
> wasn't supported for the save/restore userspace interface.

Well, I was more concerned about the reliability part in there and all
the corner cases. Not sure if anyone actually tested this from within a
guest.

>>
>> At the moment I am trying to code this explicitly into the SACTIVER
>> handler and it's messy, too (because of the corner cases).
>> Let's see how this will look like ...
> 
> ok.
> 
> If you want, you can focus on getting a new version out, and I can take
> a stab at the SACTIVER together with the priority stuff.  OTOH, if you
> already have something, then it may be worth following through with
> that.

Yeah, so by now I have something which doesn't look too bad. Copied your
style with many comments ;-)

I will now clean up the patches and try to send something out still
today. I think by now there are significantly enough changes to justify
a new revision, even if I haven't addressed every single bit of the
comments yet.

Cheers,
Andre.

P.S. There be dragons:
char device redirected to /dev/pts/0 (label serial0)
[  193.035693] Kernel panic - not syncing: HYP panic:
....

Probably due to the ->nr_lr rework, about to investigate now.


>>
>>>>
>>>>> that would also explain why we don't have to re-check the same
>>>>> conditions below...
>>>>>
>>>>> or am I getting this wrong, because you could also have someone
>>>>> explicitly setting the IRQ to active via trapped MMIO, in which case we
>>>>> should be able to queue it without it being pending && enabled, which
>>>>> would indicate that it's the other way around, you should only evaluate
>>>>> !vcpu and kup the !(pending && enabled) part....?
>>>>
>>>> You lost me here, which hints at the fragility of this optimization ;-)
>>>>
>>>>>> +		spin_unlock(&irq->irq_lock);
>>>>>> +		return false;
>>>>>> +	}
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * We must unlock the irq lock to take the ap_list_lock where
>>>>>> +	 * we are going to insert this new pending interrupt.
>>>>>> +	 */
>>>>>> +	spin_unlock(&irq->irq_lock);
>>>>>> +
>>>>>> +	/* someone can do stuff here, which we re-check below */
>>>>>> +retry:
>>>>>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>>>>>> +	spin_lock(&irq->irq_lock);
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * Did something change behind our backs?
>>>>>> +	 *
>>>>>> +	 * There are two cases:
>>>>>> +	 * 1) The irq became pending or active behind our backs and/or
>>>>>> +	 *    the irq->vcpu field was set correspondingly when putting
>>>>>> +	 *    the irq on an ap_list. Then drop the locks and return.
>>>>>> +	 * 2) Someone changed the affinity on this irq behind our
>>>>>> +	 *    backs and we are now holding the wrong ap_list_lock.
>>>>>> +	 *    Then drop the locks and try the new VCPU.
>>>>>> +	 */
>>>>>> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
>>>>>
>>>>> here I'm concerned about the active state again.
>>>>
>>>> Mmmh, can you elaborate and sketch a case where the active state would
>>>> cause trouble? This check is just here to avoid iterating on a no longer
>>>> pending or enabled IRQ. I wonder if an active IRQ can really sneak into
>>>> this function here in the first place?
>>>
>>> After having gone through the series I think we should deal with
>>> the active state queing directly in the vgic_mmio_write_sactive()
>>> function.
>>>
>>> But I still prefer to move the retry label to the very top of this
>>> function, and simplify these two statemtns to the condition I suggested:
>>>
>>> 	if (unlinkely(irq->vcpu || vcpu != vgic_target_oracle(irq)))
>>> 		goto retry;
>>>
>>> The cost is that we perform a few additional checks at runtime in the
>>> case where the IRQ was migrated while we released a lock (rare), but I
>>> think it simplifies the code.
>>
>> OK, I made this change. Also the shorter check after asking the oracle
>> above.
>> This should also better work in the case where target_vcpu is NULL
>> (because either no bit in TARGETSR is set or a non-existent MPIDR has
>> been written into IROUTER).
>>
> right.
> 
> Thanks,
> -Christoffer
> 

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

* [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-04-14 13:45               ` Andre Przywara
  0 siblings, 0 replies; 276+ messages in thread
From: Andre Przywara @ 2016-04-14 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

....

>>>>>> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
>>>>>> +		/*
>>>>>> +		 * If this IRQ is already on a VCPU's ap_list, then it
>>>>>> +		 * cannot be moved or modified and there is no more work for
>>>>>> +		 * us to do.
>>>>>> +		 *
>>>>>> +		 * Otherwise, if the irq is not pending and enabled, it does
>>>>>> +		 * not need to be inserted into an ap_list and there is also
>>>>>> +		 * no more work for us to do.
>>>>>> +		 */
>>>>>
>>>>> is the !vcpu check here not redundant because if you ever get to
>>>>> evaluating it, then irq->vcpu is null, and pending and enabled are set,
>>>>> which means the oracle couldn't have returned null, could it?
>>>>
>>>> In this case vcpu is always irq->target_vcpu, if I did the math
>>>> correctly. So can this be NULL?
>>>> Even if this is correct reasoning, I wonder if we optimize something
>>>> prematurely here and rely on the current implementation of
>>>> vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
>>>> NULL pointer deference below (in the first spin_lock after the retry:
>>>> label), so I'd rather keep this explicit check in here.
>>>
>>> I'm really not a fan of building the correctness of one of the most
>>> crucial parts of our code based on "let's add a few extra checks which
>>> may not be necessary, just in case" kind of logic.
>>>
>>> So let's be clear on why we have an if-statement here exactly:
>>>
>>> As the comment says, if we can't move the IRQ, because it's already
>>> assigned to somebody or if this IRQ is not pending or active, then it's
>>> shouldn't be queued.
>>>
>>> So the simple and all-encompassing check here is simply:
>>>
>>> 	if (irq->vcpu || !vcpu) {
>>> 		spin_unlock(&irq->irq_lock);
>>> 		return false;
>>> 	}
>>>
>>> The only requirement for this to be correct is that the MMIO handler for
>>> ISACTIVER to both set the active bit and the irq->vcpu pointer (and put
>>> it on the AP list), without calling this function...).  That was my
>>> quesiton below.
>>>
>>> Because if that's not the case, you could end up here with irq->active
>>> set, but irq->vcpu == NULL and !(pending && enabled) and you'd error
>>> out, which means you would have to check explicitly for the active state
>>> here as well, but I think that just becomes too messy.
>>>
>>> So, just change this to what I propose and we can deal with the active
>>> state MMIO handler separately.
>>
>> I agree that setting the active state via MMIO is a mess in general and
>> stuffing this case into this function here gets hairy.
>> I am tempted to not support it in the first version, I guess it never
>> really worked reliably before ...
> 
> I'm pretty sure it did, because we ran into migration breaking when this
> wasn't supported for the save/restore userspace interface.

Well, I was more concerned about the reliability part in there and all
the corner cases. Not sure if anyone actually tested this from within a
guest.

>>
>> At the moment I am trying to code this explicitly into the SACTIVER
>> handler and it's messy, too (because of the corner cases).
>> Let's see how this will look like ...
> 
> ok.
> 
> If you want, you can focus on getting a new version out, and I can take
> a stab at the SACTIVER together with the priority stuff.  OTOH, if you
> already have something, then it may be worth following through with
> that.

Yeah, so by now I have something which doesn't look too bad. Copied your
style with many comments ;-)

I will now clean up the patches and try to send something out still
today. I think by now there are significantly enough changes to justify
a new revision, even if I haven't addressed every single bit of the
comments yet.

Cheers,
Andre.

P.S. There be dragons:
char device redirected to /dev/pts/0 (label serial0)
[  193.035693] Kernel panic - not syncing: HYP panic:
....

Probably due to the ->nr_lr rework, about to investigate now.


>>
>>>>
>>>>> that would also explain why we don't have to re-check the same
>>>>> conditions below...
>>>>>
>>>>> or am I getting this wrong, because you could also have someone
>>>>> explicitly setting the IRQ to active via trapped MMIO, in which case we
>>>>> should be able to queue it without it being pending && enabled, which
>>>>> would indicate that it's the other way around, you should only evaluate
>>>>> !vcpu and kup the !(pending && enabled) part....?
>>>>
>>>> You lost me here, which hints at the fragility of this optimization ;-)
>>>>
>>>>>> +		spin_unlock(&irq->irq_lock);
>>>>>> +		return false;
>>>>>> +	}
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * We must unlock the irq lock to take the ap_list_lock where
>>>>>> +	 * we are going to insert this new pending interrupt.
>>>>>> +	 */
>>>>>> +	spin_unlock(&irq->irq_lock);
>>>>>> +
>>>>>> +	/* someone can do stuff here, which we re-check below */
>>>>>> +retry:
>>>>>> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>>>>>> +	spin_lock(&irq->irq_lock);
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * Did something change behind our backs?
>>>>>> +	 *
>>>>>> +	 * There are two cases:
>>>>>> +	 * 1) The irq became pending or active behind our backs and/or
>>>>>> +	 *    the irq->vcpu field was set correspondingly when putting
>>>>>> +	 *    the irq on an ap_list. Then drop the locks and return.
>>>>>> +	 * 2) Someone changed the affinity on this irq behind our
>>>>>> +	 *    backs and we are now holding the wrong ap_list_lock.
>>>>>> +	 *    Then drop the locks and try the new VCPU.
>>>>>> +	 */
>>>>>> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
>>>>>
>>>>> here I'm concerned about the active state again.
>>>>
>>>> Mmmh, can you elaborate and sketch a case where the active state would
>>>> cause trouble? This check is just here to avoid iterating on a no longer
>>>> pending or enabled IRQ. I wonder if an active IRQ can really sneak into
>>>> this function here in the first place?
>>>
>>> After having gone through the series I think we should deal with
>>> the active state queing directly in the vgic_mmio_write_sactive()
>>> function.
>>>
>>> But I still prefer to move the retry label to the very top of this
>>> function, and simplify these two statemtns to the condition I suggested:
>>>
>>> 	if (unlinkely(irq->vcpu || vcpu != vgic_target_oracle(irq)))
>>> 		goto retry;
>>>
>>> The cost is that we perform a few additional checks at runtime in the
>>> case where the IRQ was migrated while we released a lock (rare), but I
>>> think it simplifies the code.
>>
>> OK, I made this change. Also the shorter check after asking the oracle
>> above.
>> This should also better work in the case where target_vcpu is NULL
>> (because either no bit in TARGETSR is set or a non-existent MPIDR has
>> been written into IROUTER).
>>
> right.
> 
> Thanks,
> -Christoffer
> 

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

* Re: [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-04-14 13:45               ` Andre Przywara
@ 2016-04-14 14:05                 ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-14 14:05 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Thu, Apr 14, 2016 at 02:45:49PM +0100, Andre Przywara wrote:
> Hi,
> 
> ....
> 
> >>>>>> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
> >>>>>> +		/*
> >>>>>> +		 * If this IRQ is already on a VCPU's ap_list, then it
> >>>>>> +		 * cannot be moved or modified and there is no more work for
> >>>>>> +		 * us to do.
> >>>>>> +		 *
> >>>>>> +		 * Otherwise, if the irq is not pending and enabled, it does
> >>>>>> +		 * not need to be inserted into an ap_list and there is also
> >>>>>> +		 * no more work for us to do.
> >>>>>> +		 */
> >>>>>
> >>>>> is the !vcpu check here not redundant because if you ever get to
> >>>>> evaluating it, then irq->vcpu is null, and pending and enabled are set,
> >>>>> which means the oracle couldn't have returned null, could it?
> >>>>
> >>>> In this case vcpu is always irq->target_vcpu, if I did the math
> >>>> correctly. So can this be NULL?
> >>>> Even if this is correct reasoning, I wonder if we optimize something
> >>>> prematurely here and rely on the current implementation of
> >>>> vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
> >>>> NULL pointer deference below (in the first spin_lock after the retry:
> >>>> label), so I'd rather keep this explicit check in here.
> >>>
> >>> I'm really not a fan of building the correctness of one of the most
> >>> crucial parts of our code based on "let's add a few extra checks which
> >>> may not be necessary, just in case" kind of logic.
> >>>
> >>> So let's be clear on why we have an if-statement here exactly:
> >>>
> >>> As the comment says, if we can't move the IRQ, because it's already
> >>> assigned to somebody or if this IRQ is not pending or active, then it's
> >>> shouldn't be queued.
> >>>
> >>> So the simple and all-encompassing check here is simply:
> >>>
> >>> 	if (irq->vcpu || !vcpu) {
> >>> 		spin_unlock(&irq->irq_lock);
> >>> 		return false;
> >>> 	}
> >>>
> >>> The only requirement for this to be correct is that the MMIO handler for
> >>> ISACTIVER to both set the active bit and the irq->vcpu pointer (and put
> >>> it on the AP list), without calling this function...).  That was my
> >>> quesiton below.
> >>>
> >>> Because if that's not the case, you could end up here with irq->active
> >>> set, but irq->vcpu == NULL and !(pending && enabled) and you'd error
> >>> out, which means you would have to check explicitly for the active state
> >>> here as well, but I think that just becomes too messy.
> >>>
> >>> So, just change this to what I propose and we can deal with the active
> >>> state MMIO handler separately.
> >>
> >> I agree that setting the active state via MMIO is a mess in general and
> >> stuffing this case into this function here gets hairy.
> >> I am tempted to not support it in the first version, I guess it never
> >> really worked reliably before ...
> > 
> > I'm pretty sure it did, because we ran into migration breaking when this
> > wasn't supported for the save/restore userspace interface.
> 
> Well, I was more concerned about the reliability part in there and all
> the corner cases. Not sure if anyone actually tested this from within a
> guest.
> 

probably not.

> >>
> >> At the moment I am trying to code this explicitly into the SACTIVER
> >> handler and it's messy, too (because of the corner cases).
> >> Let's see how this will look like ...
> > 
> > ok.
> > 
> > If you want, you can focus on getting a new version out, and I can take
> > a stab at the SACTIVER together with the priority stuff.  OTOH, if you
> > already have something, then it may be worth following through with
> > that.
> 
> Yeah, so by now I have something which doesn't look too bad. Copied your
> style with many comments ;-)
> 
> I will now clean up the patches and try to send something out still
> today. I think by now there are significantly enough changes to justify
> a new revision, even if I haven't addressed every single bit of the
> comments yet.

I quite prefer you work through all the comments carefully before
sending out a new revision.

I think the key here is to improve stability and quality between each
revision as much as possible.

Also, as you know, I really don't want to go over issues I've already
commented on before.

Thanks,
-Christoffer

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

* [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-04-14 14:05                 ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2016-04-14 14:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Apr 14, 2016 at 02:45:49PM +0100, Andre Przywara wrote:
> Hi,
> 
> ....
> 
> >>>>>> +	if (irq->vcpu || !(irq->pending && irq->enabled) || !vcpu) {
> >>>>>> +		/*
> >>>>>> +		 * If this IRQ is already on a VCPU's ap_list, then it
> >>>>>> +		 * cannot be moved or modified and there is no more work for
> >>>>>> +		 * us to do.
> >>>>>> +		 *
> >>>>>> +		 * Otherwise, if the irq is not pending and enabled, it does
> >>>>>> +		 * not need to be inserted into an ap_list and there is also
> >>>>>> +		 * no more work for us to do.
> >>>>>> +		 */
> >>>>>
> >>>>> is the !vcpu check here not redundant because if you ever get to
> >>>>> evaluating it, then irq->vcpu is null, and pending and enabled are set,
> >>>>> which means the oracle couldn't have returned null, could it?
> >>>>
> >>>> In this case vcpu is always irq->target_vcpu, if I did the math
> >>>> correctly. So can this be NULL?
> >>>> Even if this is correct reasoning, I wonder if we optimize something
> >>>> prematurely here and rely on the current implementation of
> >>>> vgic_target_oracle(). I think the check for "!vcpu" is here to avoid a
> >>>> NULL pointer deference below (in the first spin_lock after the retry:
> >>>> label), so I'd rather keep this explicit check in here.
> >>>
> >>> I'm really not a fan of building the correctness of one of the most
> >>> crucial parts of our code based on "let's add a few extra checks which
> >>> may not be necessary, just in case" kind of logic.
> >>>
> >>> So let's be clear on why we have an if-statement here exactly:
> >>>
> >>> As the comment says, if we can't move the IRQ, because it's already
> >>> assigned to somebody or if this IRQ is not pending or active, then it's
> >>> shouldn't be queued.
> >>>
> >>> So the simple and all-encompassing check here is simply:
> >>>
> >>> 	if (irq->vcpu || !vcpu) {
> >>> 		spin_unlock(&irq->irq_lock);
> >>> 		return false;
> >>> 	}
> >>>
> >>> The only requirement for this to be correct is that the MMIO handler for
> >>> ISACTIVER to both set the active bit and the irq->vcpu pointer (and put
> >>> it on the AP list), without calling this function...).  That was my
> >>> quesiton below.
> >>>
> >>> Because if that's not the case, you could end up here with irq->active
> >>> set, but irq->vcpu == NULL and !(pending && enabled) and you'd error
> >>> out, which means you would have to check explicitly for the active state
> >>> here as well, but I think that just becomes too messy.
> >>>
> >>> So, just change this to what I propose and we can deal with the active
> >>> state MMIO handler separately.
> >>
> >> I agree that setting the active state via MMIO is a mess in general and
> >> stuffing this case into this function here gets hairy.
> >> I am tempted to not support it in the first version, I guess it never
> >> really worked reliably before ...
> > 
> > I'm pretty sure it did, because we ran into migration breaking when this
> > wasn't supported for the save/restore userspace interface.
> 
> Well, I was more concerned about the reliability part in there and all
> the corner cases. Not sure if anyone actually tested this from within a
> guest.
> 

probably not.

> >>
> >> At the moment I am trying to code this explicitly into the SACTIVER
> >> handler and it's messy, too (because of the corner cases).
> >> Let's see how this will look like ...
> > 
> > ok.
> > 
> > If you want, you can focus on getting a new version out, and I can take
> > a stab at the SACTIVER together with the priority stuff.  OTOH, if you
> > already have something, then it may be worth following through with
> > that.
> 
> Yeah, so by now I have something which doesn't look too bad. Copied your
> style with many comments ;-)
> 
> I will now clean up the patches and try to send something out still
> today. I think by now there are significantly enough changes to justify
> a new revision, even if I haven't addressed every single bit of the
> comments yet.

I quite prefer you work through all the comments carefully before
sending out a new revision.

I think the key here is to improve stability and quality between each
revision as much as possible.

Also, as you know, I really don't want to go over issues I've already
commented on before.

Thanks,
-Christoffer

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

end of thread, other threads:[~2016-04-14 14:05 UTC | newest]

Thread overview: 276+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-25  2:04 [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
2016-03-25  2:04 ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 01/45] KVM: arm/arm64: add missing MMIO data write-back Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-29 12:33   ` Christoffer Dall
2016-03-29 12:33     ` Christoffer Dall
2016-04-05 12:12     ` Andre Przywara
2016-04-05 12:12       ` Andre Przywara
2016-04-05 12:58       ` Christoffer Dall
2016-04-05 12:58         ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 02/45] KVM: arm/arm64: pmu: abstract access to number of SPIs Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 03/45] KVM: arm/arm64: arch_timer: rework VGIC <-> timer interface Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-29 13:01   ` Christoffer Dall
2016-03-29 13:01     ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-29 13:09   ` Christoffer Dall
2016-03-29 13:09     ` Christoffer Dall
2016-04-05 13:34     ` Andre Przywara
2016-04-05 13:34       ` Andre Przywara
2016-04-05 20:10       ` Christoffer Dall
2016-04-05 20:10         ` Christoffer Dall
2016-04-06 13:57         ` Christoffer Dall
2016-04-06 13:57           ` Christoffer Dall
2016-04-06 14:09           ` Andre Przywara
2016-04-06 14:09             ` Andre Przywara
2016-04-06 14:46             ` Christoffer Dall
2016-04-06 14:46               ` Christoffer Dall
2016-04-06 14:53               ` Andre Przywara
2016-04-06 14:53                 ` Andre Przywara
2016-04-06 14:57                 ` Christoffer Dall
2016-04-06 14:57                   ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-29 21:16   ` Christoffer Dall
2016-03-29 21:16     ` Christoffer Dall
2016-04-05 17:28     ` Andre Przywara
2016-04-05 17:28       ` Andre Przywara
2016-04-06 14:23       ` Christoffer Dall
2016-04-06 14:23         ` Christoffer Dall
2016-04-14 10:53         ` Andre Przywara
2016-04-14 10:53           ` Andre Przywara
2016-04-14 12:15           ` Christoffer Dall
2016-04-14 12:15             ` Christoffer Dall
2016-04-14 13:45             ` Andre Przywara
2016-04-14 13:45               ` Andre Przywara
2016-04-14 14:05               ` Christoffer Dall
2016-04-14 14:05                 ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 07/45] KVM: arm/arm64: vgic-new: Add vgic GICv2 change_affinity Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-30  9:29   ` Christoffer Dall
2016-03-30  9:29     ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 08/45] KVM: arm/arm64: vgic-new: Add IRQ sorting Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 IRQ sync/flush Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-30 13:53   ` Christoffer Dall
2016-03-30 13:53     ` Christoffer Dall
2016-04-05 17:57     ` Andre Przywara
2016-04-05 17:57       ` Andre Przywara
2016-04-06 14:34       ` Christoffer Dall
2016-04-06 14:34         ` Christoffer Dall
2016-03-31  9:47   ` Christoffer Dall
2016-03-31  9:47     ` Christoffer Dall
2016-04-11 11:40     ` Andre Przywara
2016-04-11 11:40       ` Andre Przywara
2016-04-12 12:25       ` Christoffer Dall
2016-04-12 12:25         ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-30 20:40   ` Christoffer Dall
2016-03-30 20:40     ` Christoffer Dall
2016-04-12 13:59     ` Andre Przywara
2016-04-12 13:59       ` Andre Przywara
2016-04-12 15:02       ` Christoffer Dall
2016-04-12 15:02         ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 11/45] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31  8:54   ` Christoffer Dall
2016-03-31  8:54     ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31  9:08   ` Christoffer Dall
2016-03-31  9:08     ` Christoffer Dall
2016-03-31  9:09     ` Christoffer Dall
2016-03-31  9:09       ` Christoffer Dall
2016-03-31 12:25       ` Paolo Bonzini
2016-03-31 12:25         ` Paolo Bonzini
2016-03-31 14:31         ` Christoffer Dall
2016-03-31 14:31           ` Christoffer Dall
2016-04-01 12:11     ` André Przywara
2016-04-01 12:11       ` André Przywara
2016-04-01 12:17       ` Christoffer Dall
2016-04-01 12:17         ` Christoffer Dall
2016-04-11 10:53     ` Andre Przywara
2016-04-11 10:53       ` Andre Przywara
2016-04-12 12:50       ` Christoffer Dall
2016-04-12 12:50         ` Christoffer Dall
2016-04-12 15:56         ` Marc Zyngier
2016-04-12 15:56           ` Marc Zyngier
2016-04-12 17:26           ` Christoffer Dall
2016-04-12 17:26             ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31  9:24   ` Christoffer Dall
2016-03-31  9:24     ` Christoffer Dall
2016-04-11 11:09     ` Andre Przywara
2016-04-11 11:09       ` Andre Przywara
2016-04-12 12:52       ` Christoffer Dall
2016-04-12 12:52         ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31  9:27   ` Christoffer Dall
2016-03-31  9:27     ` Christoffer Dall
2016-04-11 11:23     ` Andre Przywara
2016-04-11 11:23       ` Andre Przywara
2016-04-12 12:55       ` Christoffer Dall
2016-04-12 12:55         ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 15/45] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31  9:33   ` Christoffer Dall
2016-03-31  9:33     ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING " Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31  9:35   ` Christoffer Dall
2016-03-31  9:35     ` Christoffer Dall
2016-04-11 11:31     ` Andre Przywara
2016-04-11 11:31       ` Andre Przywara
2016-04-12 13:10       ` Christoffer Dall
2016-04-12 13:10         ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 17/45] KVM: arm/arm64: vgic-new: Add PRIORITY " Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31  9:50   ` Christoffer Dall
2016-03-31  9:50     ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 18/45] KVM: arm/arm64: vgic-new: Add ACTIVE " Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31  9:58   ` Christoffer Dall
2016-03-31  9:58     ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 19/45] KVM: arm/arm64: vgic-new: Add CONFIG " Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31 10:07   ` Christoffer Dall
2016-03-31 10:07     ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET " Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31 11:31   ` Christoffer Dall
2016-03-31 11:31     ` Christoffer Dall
2016-04-11 12:10     ` Andre Przywara
2016-04-11 12:10       ` Andre Przywara
2016-04-12 13:18       ` Christoffer Dall
2016-04-12 13:18         ` Christoffer Dall
2016-04-12 15:18         ` Andre Przywara
2016-04-12 15:18           ` Andre Przywara
2016-04-12 15:26           ` Christoffer Dall
2016-04-12 15:26             ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 21/45] KVM: arm/arm64: vgic-new: Add SGIR register handler Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31 11:35   ` Christoffer Dall
2016-03-31 11:35     ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 22/45] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31 11:37   ` Christoffer Dall
2016-03-31 11:37     ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 emulation framework Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31 11:48   ` Christoffer Dall
2016-03-31 11:48     ` Christoffer Dall
2016-04-11 12:44     ` Andre Przywara
2016-04-11 12:44       ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31 11:53   ` Christoffer Dall
2016-03-31 11:53     ` Christoffer Dall
2016-04-11 13:00     ` Andre Przywara
2016-04-11 13:00       ` Andre Przywara
2016-04-12 13:20       ` Christoffer Dall
2016-04-12 13:20         ` Christoffer Dall
2016-03-25  2:04 ` [RFC PATCH 25/45] KVM: arm/arm64: vgic-new: Add GICv3 redistributor TYPER handler Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 27/45] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-31 12:07   ` Christoffer Dall
2016-03-31 12:07     ` Christoffer Dall
2016-04-11 13:11     ` Andre Przywara
2016-04-11 13:11       ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 29/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 30/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 31/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 32/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 33/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 34/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 35/45] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:04 ` [RFC PATCH 36/45] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors Andre Przywara
2016-03-25  2:04   ` Andre Przywara
2016-03-25  2:05 ` [RFC PATCH 37/45] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access Andre Przywara
2016-03-25  2:05   ` Andre Przywara
2016-03-25  2:05 ` [RFC PATCH 38/45] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init Andre Przywara
2016-03-25  2:05   ` Andre Przywara
2016-03-25  2:05 ` [RFC PATCH 39/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create Andre Przywara
2016-03-25  2:05   ` Andre Przywara
2016-03-25  2:05 ` [RFC PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init Andre Przywara
2016-03-25  2:05   ` Andre Przywara
2016-03-31 17:59   ` Christoffer Dall
2016-03-31 17:59     ` Christoffer Dall
2016-04-01  8:20     ` Eric Auger
2016-04-01  8:20       ` Eric Auger
2016-04-01  9:00       ` Christoffer Dall
2016-04-01  9:00         ` Christoffer Dall
2016-03-25  2:05 ` [RFC PATCH 41/45] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources Andre Przywara
2016-03-25  2:05   ` Andre Przywara
2016-03-25  2:05 ` [RFC PATCH 42/45] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable Andre Przywara
2016-03-25  2:05   ` Andre Przywara
2016-03-25  2:05 ` [RFC PATCH 43/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling Andre Przywara
2016-03-25  2:05   ` Andre Przywara
2016-03-31 18:15   ` Christoffer Dall
2016-03-31 18:15     ` Christoffer Dall
2016-04-01  8:44     ` Eric Auger
2016-04-01  8:44       ` Eric Auger
2016-03-25  2:05 ` [RFC PATCH 44/45] KVM: arm/arm64: vgic-new: Add dummy MSI implementation Andre Przywara
2016-03-25  2:05   ` Andre Przywara
2016-03-31 18:16   ` Christoffer Dall
2016-03-31 18:16     ` Christoffer Dall
2016-04-07 14:35     ` Eric Auger
2016-04-07 14:35       ` Eric Auger
2016-03-25  2:05 ` [RFC PATCH 45/45] KVM: arm/arm64: vgic-new: enable build Andre Przywara
2016-03-25  2:05   ` Andre Przywara
2016-03-31 18:18   ` Christoffer Dall
2016-03-31 18:18     ` Christoffer Dall
2016-04-11 14:45     ` Andre Przywara
2016-04-11 14:45       ` Andre Przywara
2016-04-12 13:21       ` Christoffer Dall
2016-04-12 13:21         ` Christoffer Dall
2016-03-25 15:58 ` [RFC PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Diana Madalina Craciun
2016-03-25 15:58   ` Diana Madalina Craciun
2016-03-26  2:11 ` André Przywara
2016-03-26  2:11   ` André Przywara
2016-03-29 13:12 ` Vladimir Murzin
2016-03-29 13:12   ` Vladimir Murzin
2016-03-30 11:42   ` Vladimir Murzin
2016-03-30 11:42     ` Vladimir Murzin
2016-03-30 11:52     ` Vladimir Murzin
2016-03-30 11:52       ` Vladimir Murzin
2016-03-30 13:56       ` Christoffer Dall
2016-03-30 13:56         ` Christoffer Dall
2016-03-30 14:13         ` Vladimir Murzin
2016-03-30 14:13           ` Vladimir Murzin
2016-03-30 19:53           ` Christoffer Dall
2016-03-30 19:53             ` Christoffer Dall
2016-03-30 12:07     ` Marc Zyngier
2016-03-30 12:07       ` Marc Zyngier
2016-03-30 19:55       ` Christoffer Dall
2016-03-30 19:55         ` Christoffer Dall
2016-03-31  9:06         ` Marc Zyngier
2016-03-31  9:06           ` Marc Zyngier
2016-03-31 18:28 ` Christoffer Dall
2016-03-31 18:28   ` Christoffer Dall
2016-03-31 18:30 ` Christoffer Dall
2016-03-31 18:30   ` Christoffer Dall
2016-04-13 16:07   ` André Przywara
2016-04-13 16:07     ` André Przywara
2016-04-13 17:24     ` Christoffer Dall
2016-04-13 17:24       ` Christoffer Dall

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.