* [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-04-28 16:45 Andre Przywara
2016-04-28 16:45 ` [PATCH v2 01/54] KVM: arm/arm64: vgic: streamline vgic_update_irq_pending() interface Andre Przywara
` (53 more replies)
0 siblings, 54 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
this is another rework of the new VGIC series.
Most prominent changes this time include a complete rewrite of the MMIO
framework and splitting the emulation bits for GICv2 and GICv3 into
separate files (patch 20/54 and 21/54) - many thanks to Christoffer and
Marc for taking care of that.
We dropped support for userland save and restore of any GICv3 register,
as the ABI hasn't been fully agreed upon.
Also the arch_timer rework series has now been integrated (making up
the first seven patches), since it's a prerequisite for the new VGIC
and also not very useful without it.
Some fixes - especially for GICv3 emulation - have also been integrated.
The file names have been trimmed to all using dashes instead of a mixture
of dashes and underscores.
The patches that saw changes have had their changelog updated.
All the open issues that were mentioned in the last cover letter have
either been addressed or dismissed.
The series survived some testing on various hosts - both GICv2 and
GICv3, also 32-bit GICv2 hosts - and various guests.
Some basic cross-endian tests were done as well, with both 64-bit LE and
BE guests surviving boot and hackbench runs on a 64-bit BE host.
Also a 32-bit BE guest was booted successfully on a 64-bit LE host.
As this new VGIC emulation will probably become the default very shortly,
please test it full steam on whatever setup you have access to.
Any reports are warmly welcome.
This series is now based on v4.6-rc5.
A git tree containing this series can be found on linux-arm.org:
git://linux-arm.org/linux-ap.git branch: vgic-new/v2
http://www.linux-arm.org/git?p=linux-ap.git;a=log;h=refs/heads/vgic-new/v2
Cheers,
Andre.
===========================
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
structure, which holds all information about a virtual interrupt.
Interruts which should be injected are held 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 (28):
KVM: arm/arm64: vgic: streamline vgic_update_irq_pending() interface
KVM: arm/arm64: vgic: avoid map in kvm_vgic_inject_mapped_irq()
KVM: arm/arm64: vgic: avoid map in kvm_vgic_map_is_active()
KVM: arm/arm64: vgic: avoid map in kvm_vgic_unmap_phys_irq()
KVM: arm/arm64: arch_timer: Remove irq_phys_map
KVM: arm/arm64: vgic: Remove irq_phys_map from interface
KVM: arm/arm64: pmu: abstract access to number of SPIs
KVM: arm/arm64: vgic-new: Add GICv2 MMIO handling framework
KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
KVM: arm/arm64: vgic-new: Add PENDING registers handlers
KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
KVM: arm/arm64: vgic-new: Add PRIORITY 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 MMIO handling framework
KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and 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: Wire up irqfd injection
KVM: arm/arm64: vgic-new: implement mapped IRQ handling
KVM: arm/arm64: vgic-new: enable build
Christoffer Dall (9):
KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map
KVM: arm/arm64: Get rid of vgic_cpu->nr_lr
KVM: arm/arm64: Fix MMIO emulation data handling
KVM: arm/arm64: Export mmio_read/write_bus
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 IRQ sorting
KVM: arm/arm64: vgic-new: Export register access interface
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 (5):
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: Add MMIO handling framework
KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
arch/arm/include/asm/kvm_mmio.h | 3 +
arch/arm/kvm/Kconfig | 7 +
arch/arm/kvm/Makefile | 11 +
arch/arm/kvm/mmio.c | 24 +-
arch/arm64/include/asm/kvm_mmio.h | 3 +
arch/arm64/kvm/Kconfig | 7 +
arch/arm64/kvm/Makefile | 12 +
include/kvm/arm_arch_timer.h | 3 -
include/kvm/arm_vgic.h | 20 +-
include/kvm/vgic/vgic.h | 253 +++++++++++++++
include/linux/irqchip/arm-gic-v3.h | 1 +
include/linux/irqchip/arm-gic.h | 2 +
virt/kvm/arm/arch_timer.c | 43 ++-
virt/kvm/arm/hyp/vgic-v2-sr.c | 17 +-
virt/kvm/arm/pmu.c | 2 +-
virt/kvm/arm/vgic-v2.c | 4 +-
virt/kvm/arm/vgic.c | 86 ++---
virt/kvm/arm/vgic/vgic-init.c | 446 +++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-irqfd.c | 52 +++
virt/kvm/arm/vgic/vgic-kvm-device.c | 522 +++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio-v2.c | 312 ++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio-v3.c | 464 ++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.c | 523 ++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.h | 128 ++++++++
virt/kvm/arm/vgic/vgic-v2.c | 358 ++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v3.c | 335 +++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 631 ++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 122 +++++++
28 files changed, 4285 insertions(+), 106 deletions(-)
create mode 100644 include/kvm/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-v2.c
create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
create mode 100644 virt/kvm/arm/vgic/vgic-mmio.c
create mode 100644 virt/kvm/arm/vgic/vgic-mmio.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
--
2.7.3
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 01/54] KVM: arm/arm64: vgic: streamline vgic_update_irq_pending() interface
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 02/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_inject_mapped_irq() Andre Przywara
` (52 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
We actually don't use the irq_phys_map parameter in
vgic_update_irq_pending(), so let's just remove it.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
virt/kvm/arm/vgic.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00429b3..7282881 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -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,7 +1660,7 @@ 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);
}
/**
@@ -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, map->virt_irq, level);
}
static irqreturn_t vgic_maintenance_handler(int irq, void *data)
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 02/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_inject_mapped_irq()
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
2016-04-28 16:45 ` [PATCH v2 01/54] KVM: arm/arm64: vgic: streamline vgic_update_irq_pending() interface Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 03/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_map_is_active() Andre Przywara
` (51 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
When we want to inject a hardware mapped IRQ into a guest, we actually
only need the virtual IRQ number from the irq_phys_map.
So let's pass this number directly from the arch timer to the VGIC
to avoid using the map as a parameter.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
include/kvm/arm_vgic.h | 2 +-
virt/kvm/arm/arch_timer.c | 2 +-
virt/kvm/arm/vgic.c | 6 +++---
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 281caf8..c4574da 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -341,7 +341,7 @@ 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);
+ unsigned 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,
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 9aaa35d..ceec146 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -178,7 +178,7 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->map->virt_irq,
timer->irq.level);
ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
- timer->map,
+ timer->map->virt_irq,
timer->irq.level);
WARN_ON(ret);
}
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 7282881..9937d41 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1667,7 +1667,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
* 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
@@ -1678,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)
+ unsigned int virt_irq, bool level)
{
int ret;
@@ -1686,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->virt_irq, level);
+ return vgic_update_irq_pending(kvm, cpuid, virt_irq, level);
}
static irqreturn_t vgic_maintenance_handler(int irq, void *data)
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 03/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_map_is_active()
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
2016-04-28 16:45 ` [PATCH v2 01/54] KVM: arm/arm64: vgic: streamline vgic_update_irq_pending() interface Andre Przywara
2016-04-28 16:45 ` [PATCH v2 02/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_inject_mapped_irq() Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 04/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_unmap_phys_irq() Andre Przywara
` (50 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
For getting the active state of a mapped IRQ, we actually only need
the virtual IRQ number, not the pointer to the mapping entry.
Pass the virtual IRQ number from the arch timer to the VGIC directly.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog v1 .. v2:
- rewrap phys_active determination to fit in 80 characters
include/kvm/arm_vgic.h | 2 +-
virt/kvm/arm/arch_timer.c | 6 ++----
virt/kvm/arm/vgic.c | 6 +++---
3 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index c4574da..5a34adc 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -347,7 +347,7 @@ 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);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned 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 ceec146..f601471 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -275,10 +275,8 @@ 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))
- phys_active = true;
- else
- phys_active = false;
+ phys_active = timer->irq.level ||
+ kvm_vgic_map_is_active(vcpu, timer->map->virt_irq);
/*
* We want to avoid hitting the (re)distributor as much as
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 9937d41..6911327 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, unsigned 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);
}
/*
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 04/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_unmap_phys_irq()
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (2 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 03/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_map_is_active() Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 05/54] KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map Andre Przywara
` (49 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
kvm_vgic_unmap_phys_irq() only needs the virtual IRQ number, so let's
just pass that between the arch timer and the VGIC to get rid of
the irq_phys_map pointer.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
include/kvm/arm_vgic.h | 2 +-
virt/kvm/arm/arch_timer.c | 2 +-
virt/kvm/arm/vgic.c | 11 ++++-------
3 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 5a34adc..43eeb18 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -346,7 +346,7 @@ 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);
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
#define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel))
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index f601471..58b2439 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -504,7 +504,7 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
timer_disarm(timer);
if (timer->map)
- kvm_vgic_unmap_phys_irq(vcpu, timer->map);
+ kvm_vgic_unmap_phys_irq(vcpu, timer->map->virt_irq);
}
void kvm_timer_enable(struct kvm *kvm)
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 6911327..2d7ae35 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1813,25 +1813,22 @@ static void vgic_free_phys_irq_map_rcu(struct rcu_head *rcu)
/**
* kvm_vgic_unmap_phys_irq - Remove a virtual to physical IRQ mapping
* @vcpu: The VCPU pointer
- * @map: The pointer to a mapping obtained through kvm_vgic_map_phys_irq
+ * @virt_irq: The virtual IRQ number to be unmapped
*
* 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, unsigned int virt_irq)
{
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
struct irq_phys_map_entry *entry;
struct list_head *root;
- if (!map)
- return -EINVAL;
-
- root = vgic_get_irq_phys_map_list(vcpu, map->virt_irq);
+ root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
spin_lock(&dist->irq_phys_map_lock);
list_for_each_entry(entry, root, entry) {
- if (&entry->map == map) {
+ if (entry->map.virt_irq == virt_irq) {
list_del_rcu(&entry->entry);
call_rcu(&entry->rcu, vgic_free_phys_irq_map_rcu);
break;
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 05/54] KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (3 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 04/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_unmap_phys_irq() Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-05-03 12:15 ` Marc Zyngier
2016-04-28 16:45 ` [PATCH v2 06/54] KVM: arm/arm64: arch_timer: Remove irq_phys_map Andre Przywara
` (48 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
From: Christoffer Dall <christoffer.dall@linaro.org>
The communication of a Linux IRQ number from outside the VGIC to the
vgic was a leftover from the day when the vgic code cared about how a
particular device injects virtual interrupts mapped to a physical
interrupt.
We can safely remove this notion, leaving all physical IRQ handling to
be done in the device driver (the arch timer in this case), which makes
room for a saner API for the new VGIC.
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog v1 .. v2:
- update kerneldoc comments on kvm_vgic_map_phys_irq()
include/kvm/arm_vgic.h | 3 +--
virt/kvm/arm/arch_timer.c | 22 ++++++++++++++++++++--
virt/kvm/arm/vgic.c | 28 ++++++----------------------
3 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 43eeb18..49c559e 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, unsigned int virt_irq);
bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 58b2439..b470632 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -301,7 +301,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);
@@ -334,6 +334,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
@@ -353,10 +356,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 2d7ae35..41792c0 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1712,38 +1712,24 @@ static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu,
/**
* kvm_vgic_map_phys_irq - map a virtual IRQ to a physical IRQ
* @vcpu: The VCPU pointer
- * @virt_irq: The virtual irq number
- * @irq: The Linux IRQ number
+ * @virt_irq: The virtual IRQ number for the guest
+ * @phys_irq: The hardware IRQ number of the host
*
* Establish a mapping between a guest visible irq (@virt_irq) and a
- * Linux irq (@irq). On injection, @virt_irq will be associated with
- * the physical interrupt represented by @irq. This mapping can be
+ * hardware irq (@phys_irq). On injection, @virt_irq will be associated with
+ * the physical interrupt represented by @phys_irq. This mapping can be
* established multiple times as long as the parameters are the same.
*
* 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);
@@ -1756,8 +1742,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 */
@@ -1767,7 +1752,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);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 06/54] KVM: arm/arm64: arch_timer: Remove irq_phys_map
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (4 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 05/54] KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-05-02 16:44 ` Eric Auger
2016-04-28 16:45 ` [PATCH v2 07/54] KVM: arm/arm64: vgic: Remove irq_phys_map from interface Andre Przywara
` (47 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
Now that the interface between the arch timer and the VGIC does not
require passing the irq_phys_map entry pointer anymore, let's remove
it from the virtual arch timer and use the virtual IRQ number instead
directly.
The remaining pointer returned by kvm_vgic_map_phys_irq() will be
removed in the following patch.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- remove extra virt_irq member from struct, instead use irq.irq directly
include/kvm/arm_arch_timer.h | 3 ---
virt/kvm/arm/arch_timer.c | 11 +++++------
2 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index b651aed..a47b7de 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -53,9 +53,6 @@ struct arch_timer_cpu {
/* Timer IRQ */
struct kvm_irq_level irq;
- /* VGIC mapping */
- struct irq_phys_map *map;
-
/* Active IRQ state caching */
bool active_cleared_last;
};
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index b470632..3a74b17 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -175,10 +175,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->virt_irq,
+ timer->irq.irq,
timer->irq.level);
WARN_ON(ret);
}
@@ -276,7 +276,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
* exit.
*/
phys_active = timer->irq.level ||
- kvm_vgic_map_is_active(vcpu, timer->map->virt_irq);
+ kvm_vgic_map_is_active(vcpu, timer->irq.irq);
/*
* We want to avoid hitting the (re)distributor as much as
@@ -378,7 +378,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
if (WARN_ON(IS_ERR(map)))
return PTR_ERR(map);
- timer->map = map;
return 0;
}
@@ -521,8 +520,8 @@ 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->virt_irq);
+ if (timer->irq.irq)
+ kvm_vgic_unmap_phys_irq(vcpu, timer->irq.irq);
}
void kvm_timer_enable(struct kvm *kvm)
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 07/54] KVM: arm/arm64: vgic: Remove irq_phys_map from interface
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (5 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 06/54] KVM: arm/arm64: arch_timer: Remove irq_phys_map Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-05-03 22:22 ` Tom Hanson
2016-04-28 16:45 ` [PATCH v2 08/54] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr Andre Przywara
` (46 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
Now that the virtual arch timer does not care about the irq_phys_map
anymore, let's rework kvm_vgic_map_phys_irq() to return an error
value instead. Any reference to that mapping can later be done by
passing the correct combination of VCPU and virtual IRQ number.
This makes the irq_phys_map handling completely private to the
VGIC code.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog v1 .. v2:
- adaptations to changes in previous patches (removal of virt_irq)
include/kvm/arm_vgic.h | 3 +--
virt/kvm/arm/arch_timer.c | 8 ++++----
virt/kvm/arm/vgic.c | 15 +++++++--------
3 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 49c559e..f842d7d 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -343,8 +343,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
unsigned 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 phys_irq);
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int virt_irq, int phys_irq);
int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 3a74b17..9475000 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -333,10 +333,10 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
const struct kvm_irq_level *irq)
{
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;
+ int ret;
/*
* The vcpu timer irq number cannot be determined in
@@ -374,9 +374,9 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
* 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, phys_irq);
- if (WARN_ON(IS_ERR(map)))
- return PTR_ERR(map);
+ ret = kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
+ if (ret)
+ return ret;
return 0;
}
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 41792c0..00386df 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1720,21 +1720,20 @@ static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu,
* the physical interrupt represented by @phys_irq. This mapping can be
* established multiple times as long as the parameters are the same.
*
- * Returns a valid pointer on success, and an error pointer otherwise
+ * Returns 0 on success or an error value otherwise.
*/
-struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
- int virt_irq, int phys_irq)
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, 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;
-
+ int ret = 0;
/* Create a new mapping */
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
spin_lock(&dist->irq_phys_map_lock);
@@ -1743,7 +1742,7 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
if (map) {
/* Make sure this mapping matches */
if (map->phys_irq != phys_irq)
- map = ERR_PTR(-EINVAL);
+ ret = -EINVAL;
/* Found an existing, valid mapping */
goto out;
@@ -1759,9 +1758,9 @@ out:
spin_unlock(&dist->irq_phys_map_lock);
/* If we've found a hit in the existing list, free the useless
* entry */
- if (IS_ERR(map) || map != &entry->map)
+ if (ret || map != &entry->map)
kfree(entry);
- return map;
+ return ret;
}
static struct irq_phys_map *vgic_irq_map_search(struct kvm_vcpu *vcpu,
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 08/54] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (6 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 07/54] KVM: arm/arm64: vgic: Remove irq_phys_map from interface Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 09/54] KVM: arm/arm64: Fix MMIO emulation data handling Andre Przywara
` (45 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
From: Christoffer Dall <christoffer.dall@linaro.org>
The number of list registers is a property of the underlying system, not
of emulated VGIC CPU interface.
As we are about to move this variable to global state in the new vgic
for clarity, move it from the legacy implementation as well to make the
merge of the new code easier.
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
include/kvm/arm_vgic.h | 3 ---
virt/kvm/arm/hyp/vgic-v2-sr.c | 12 +++++++-----
virt/kvm/arm/vgic-v2.c | 4 +++-
virt/kvm/arm/vgic.c | 12 ++----------
4 files changed, 12 insertions(+), 19 deletions(-)
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index f842d7d..452bb85 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -303,9 +303,6 @@ struct vgic_cpu {
unsigned long *active_shared;
unsigned long *pend_act_shared;
- /* Number of list registers on this CPU */
- int nr_lr;
-
/* CPU vif control registers for world switch */
union {
struct vgic_v2_cpu_if vgic_v2;
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 674bdf8..caac41f 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -21,11 +21,13 @@
#include <asm/kvm_hyp.h>
+extern struct vgic_params vgic_v2_params;
+
static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
void __iomem *base)
{
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
- int nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+ int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
u32 eisr0, eisr1;
int i;
bool expect_mi;
@@ -67,7 +69,7 @@ static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
{
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
- int nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+ int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
u32 elrsr0, elrsr1;
elrsr0 = readl_relaxed(base + GICH_ELRSR0);
@@ -86,7 +88,7 @@ static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
{
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
- int nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+ int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
int i;
for (i = 0; i < nr_lr; i++) {
@@ -141,13 +143,13 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
struct vgic_dist *vgic = &kvm->arch.vgic;
void __iomem *base = kern_hyp_va(vgic->vctrl_base);
- int i, nr_lr;
+ int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
+ int i;
u64 live_lrs = 0;
if (!base)
return;
- nr_lr = vcpu->arch.vgic_cpu.nr_lr;
for (i = 0; i < nr_lr; i++)
if (cpu_if->vgic_lr[i] & GICH_LR_STATE)
diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c
index 67ec334..6aaf5f7 100644
--- a/virt/kvm/arm/vgic-v2.c
+++ b/virt/kvm/arm/vgic-v2.c
@@ -174,7 +174,7 @@ static const struct vgic_ops vgic_v2_ops = {
.enable = vgic_v2_enable,
};
-static struct vgic_params vgic_v2_params;
+struct vgic_params __section(.hyp.text) vgic_v2_params;
static void vgic_cpu_init_lrs(void *params)
{
@@ -204,6 +204,8 @@ int vgic_v2_probe(struct device_node *vgic_node,
struct resource vcpu_res;
struct vgic_params *vgic = &vgic_v2_params;
+ memset(vgic, 0, sizeof(*vgic));
+
vgic->maint_irq = irq_of_parse_and_map(vgic_node, 0);
if (!vgic->maint_irq) {
kvm_err("error getting vgic maintenance irq from DT\n");
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00386df..5efc298 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -691,12 +691,11 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
*/
void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
{
- struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
u64 elrsr = vgic_get_elrsr(vcpu);
unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
int i;
- for_each_clear_bit(i, elrsr_ptr, vgic_cpu->nr_lr) {
+ for_each_clear_bit(i, elrsr_ptr, vgic->nr_lr) {
struct vgic_lr lr = vgic_get_lr(vcpu, i);
/*
@@ -1107,7 +1106,7 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
{
int i;
- for (i = 0; i < vcpu->arch.vgic_cpu.nr_lr; i++) {
+ for (i = 0; i < vgic->nr_lr; i++) {
struct vgic_lr vlr = vgic_get_lr(vcpu, i);
if (vlr.irq == virt_irq && vlr.state & LR_STATE_ACTIVE)
@@ -1867,13 +1866,6 @@ static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
return -ENOMEM;
}
- /*
- * Store the number of LRs per vcpu, so we don't have to go
- * all the way to the distributor structure to find out. Only
- * assembly code should use this one.
- */
- vgic_cpu->nr_lr = vgic->nr_lr;
-
return 0;
}
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 09/54] KVM: arm/arm64: Fix MMIO emulation data handling
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (7 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 08/54] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 10/54] KVM: arm/arm64: Export mmio_read/write_bus Andre Przywara
` (44 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
From: Christoffer Dall <christoffer.dall@linaro.org>
When the kernel was handling a guest MMIO read 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 the upcoming new vgic implementation we need this done
properly.
Update the kvm_handle_mmio_return description and cleanup the code to
only perform a single copying when needed.
Code and commit message inspired by Andre Przywara.
Reported-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
arch/arm/kvm/mmio.c | 14 +++++++-------
virt/kvm/arm/vgic.c | 7 -------
2 files changed, 7 insertions(+), 14 deletions(-)
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 5efc298..e70cee4 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -820,7 +820,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
struct vgic_io_device *iodev = container_of(this,
struct vgic_io_device, dev);
- struct kvm_run *run = vcpu->run;
const struct vgic_io_range *range;
struct kvm_exit_mmio mmio;
bool updated_state;
@@ -849,12 +848,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);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 10/54] KVM: arm/arm64: Export mmio_read/write_bus
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (8 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 09/54] KVM: arm/arm64: Fix MMIO emulation data handling Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 11/54] KVM: arm/arm64: pmu: abstract access to number of SPIs Andre Przywara
` (43 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
From: Christoffer Dall <christoffer.dall@linaro.org>
Rename mmio_{read,write}_bus to kvm_mmio_{read,write}_bus and export
them out of mmio.c.
This will be needed later for the new VGIC implementation.
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
arch/arm/include/asm/kvm_mmio.h | 3 +++
arch/arm/kvm/mmio.c | 10 +++++-----
arch/arm64/include/asm/kvm_mmio.h | 3 +++
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/arch/arm/include/asm/kvm_mmio.h b/arch/arm/include/asm/kvm_mmio.h
index d8e90c8..f3a7de7 100644
--- a/arch/arm/include/asm/kvm_mmio.h
+++ b/arch/arm/include/asm/kvm_mmio.h
@@ -28,6 +28,9 @@ struct kvm_decode {
bool sign_extend;
};
+void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
+unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
+
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
phys_addr_t fault_ipa);
diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 0158e9e..10f80a6 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -23,7 +23,7 @@
#include "trace.h"
-static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
+void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data)
{
void *datap = NULL;
union {
@@ -55,7 +55,7 @@ static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
memcpy(buf, datap, len);
}
-static unsigned long mmio_read_buf(char *buf, unsigned int len)
+unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len)
{
unsigned long data = 0;
union {
@@ -66,7 +66,7 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
switch (len) {
case 1:
- data = buf[0];
+ data = *(u8 *)buf;
break;
case 2:
memcpy(&tmp.hword, buf, len);
@@ -103,7 +103,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
if (len > sizeof(unsigned long))
return -EINVAL;
- data = mmio_read_buf(run->mmio.data, len);
+ data = kvm_mmio_read_buf(run->mmio.data, len);
if (vcpu->arch.mmio_decode.sign_extend &&
len < sizeof(unsigned long)) {
@@ -189,7 +189,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
len);
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
- mmio_write_buf(data_buf, len, data);
+ kvm_mmio_write_buf(data_buf, len, data);
ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
data_buf);
diff --git a/arch/arm64/include/asm/kvm_mmio.h b/arch/arm64/include/asm/kvm_mmio.h
index fe612a9..75ea420 100644
--- a/arch/arm64/include/asm/kvm_mmio.h
+++ b/arch/arm64/include/asm/kvm_mmio.h
@@ -30,6 +30,9 @@ struct kvm_decode {
bool sign_extend;
};
+void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
+unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
+
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
phys_addr_t fault_ipa);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 11/54] KVM: arm/arm64: pmu: abstract access to number of SPIs
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (9 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 10/54] KVM: arm/arm64: Export mmio_read/write_bus Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 12/54] KVM: arm/arm64: vgic-new: Add data structure definitions Andre Przywara
` (42 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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 452bb85..c14ff77 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -347,6 +347,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
#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 575c7aa..bd2e872 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -477,7 +477,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] 94+ messages in thread
* [PATCH v2 12/54] KVM: arm/arm64: vgic-new: Add data structure definitions
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (10 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 11/54] KVM: arm/arm64: pmu: abstract access to number of SPIs Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 13/54] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance Andre Przywara
` (41 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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>
---
Changes RFC .. v1:
- adapt to 4.6-rc (adding live_lrs member)
- elaborate on ap_list usage
Changes v1 .. v2:
- change data type of dist->enabled to bool
include/kvm/arm_vgic.h | 5 ++
include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 206 insertions(+)
create mode 100644 include/kvm/vgic/vgic.h
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index c14ff77..d406f8e 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>
@@ -366,4 +370,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..39933ee
--- /dev/null
+++ b/include/kvm/vgic/vgic.h
@@ -0,0 +1,201 @@
+/*
+ * 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 */
+ bool 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;
+ };
+
+ 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 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;
+
+ u64 live_lrs;
+};
+
+#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] 94+ messages in thread
* [PATCH v2 13/54] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (11 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 12/54] KVM: arm/arm64: vgic-new: Add data structure definitions Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 14/54] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection Andre Przywara
` (40 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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..fb45537
--- /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 __section(.hyp.text) 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] 94+ messages in thread
* [PATCH v2 14/54] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (12 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 13/54] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-05-03 23:46 ` Tom Hanson
2016-04-28 16:45 ` [PATCH v2 15/54] KVM: arm/arm64: vgic-new: Add IRQ sorting Andre Przywara
` (39 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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 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_unlock()]
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- add spinlock checks protected by CONFIG_DEBUG_SPINLOCK
- add more comments to vgic_target_oracle
- remove BUG_ON() if IRQ is neither edge or level
- rename vgic_queue_irq() to vgic_queue_irq_unlock()
- simplify initial check in vgic_queue_irq_unlock()
- extend retry loop to ask the oracle again
- minor comment fixes
Changelog v1 .. v2:
- move most IRQ injection code into vgic_update_irq_pending()
include/kvm/vgic/vgic.h | 3 +
virt/kvm/arm/vgic/vgic.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 213 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 39933ee..2bfb42c 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -181,6 +181,9 @@ struct vgic_cpu {
u64 live_lrs;
};
+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 fb45537..92b78a0 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -19,8 +19,31 @@
#include "vgic.h"
+#define CREATE_TRACE_POINTS
+#include "../trace.h"
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+#define DEBUG_SPINLOCK_BUG_ON(p) BUG_ON(p)
+#else
+#define DEBUG_SPINLOCK_BUG_ON(p)
+#endif
+
struct vgic_global __section(.hyp.text) 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 +62,189 @@ 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.
+ *
+ * Requires the IRQ lock to be held.
+ */
+static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
+{
+ DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+
+ /* If the interrupt is active, it must stay on the current vcpu */
+ if (irq->active)
+ return irq->vcpu;
+
+ /*
+ * 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;
+
+ /* 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;
+ }
+
+ return false;
+}
+
+/*
+ * 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_unlock(struct kvm *kvm, struct vgic_irq *irq)
+{
+ struct kvm_vcpu *vcpu;
+
+ DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+
+retry:
+ vcpu = vgic_target_oracle(irq);
+ if (irq->vcpu || !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 */
+
+ 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);
+
+ spin_lock(&irq->irq_lock);
+ 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 int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
+ unsigned int intid, bool level,
+ bool mapped_irq)
+{
+ struct kvm_vcpu *vcpu;
+ struct vgic_irq *irq;
+ int ret;
+
+ trace_vgic_update_irq_pending(cpuid, intid, level);
+
+ vcpu = kvm_get_vcpu(kvm, cpuid);
+ if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
+ return -EINVAL;
+
+ irq = vgic_get_irq(kvm, vcpu, intid);
+ if (!irq)
+ return -EINVAL;
+
+ if (irq->hw != mapped_irq)
+ return -EINVAL;
+
+ spin_lock(&irq->irq_lock);
+
+ if (!vgic_validate_injection(irq, level)) {
+ /* Nothing to see here, move along... */
+ spin_unlock(&irq->irq_lock);
+ return 0;
+ }
+
+ if (irq->config == VGIC_CONFIG_LEVEL) {
+ irq->line_level = level;
+ irq->pending = level || irq->soft_pending;
+ } else {
+ irq->pending = true;
+ }
+
+ vgic_queue_irq_unlock(kvm, irq);
+
+ return 0;
+}
+
+/**
+ * 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.
+ * @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 VGIC 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)
+{
+ return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 61b8d22..c625767 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_unlock(struct kvm *kvm, struct vgic_irq *irq);
#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 15/54] KVM: arm/arm64: vgic-new: Add IRQ sorting
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (13 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 14/54] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 16/54] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework Andre Przywara
` (38 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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 | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 92b78a0..4fb20fd 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"
@@ -96,6 +97,62 @@ 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)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
+ DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
+
+ list_sort(NULL, &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] 94+ messages in thread
* [PATCH v2 16/54] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (14 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 15/54] KVM: arm/arm64: vgic-new: Add IRQ sorting Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-05-05 16:23 ` Tom Hanson
2016-04-28 16:45 ` [PATCH v2 17/54] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend Andre Przywara
` (37 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
From: Marc Zyngier <marc.zyngier@arm.com>
Implement the framework 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.
The code talking to the actual GICv2/v3 hardware is added in the
following patches.
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>
---
Changelog RFC..v1:
- split out vgic_clear_lr() from vgic_populate_lr()
- rename vgic_populate_lrs() to vgic_flush_lr_state()
- clean all LRs when the distributor is disabled
- use list_del() instead of list_del_init()
- add comments to explain the direction of sync/flush_hwstate
- remove unneeded BUG_ON(in_interrupt()
include/kvm/vgic/vgic.h | 4 +
virt/kvm/arm/vgic/vgic.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 2 +
3 files changed, 206 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2bfb42c..5fae4a9 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -190,6 +190,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.c b/virt/kvm/arm/vgic/vgic.c
index 4fb20fd..a656a12e5 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -305,3 +305,203 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
{
return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
}
+
+/**
+ * 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(&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(&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)
+{
+}
+
+static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+}
+
+/* Requires the ap_list_lock and the irq_lock to be held. */
+static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
+ struct vgic_irq *irq, int lr)
+{
+ DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
+ DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+}
+
+static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+}
+
+static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
+{
+}
+
+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 (vgic_irq_is_sgi(irq->intid) && irq->source)
+ count += hweight8(irq->source);
+ else
+ count++;
+ spin_unlock(&irq->irq_lock);
+ }
+ return count;
+}
+
+/* Requires the VCPU's ap_list_lock to be held. */
+static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ u32 model = dist->vgic_model;
+ struct vgic_irq *irq;
+ int count = 0;
+
+ DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(vgic_cpu->ap_list_lock));
+
+ if (unlikely(!dist->enabled))
+ goto out_clean;
+
+ if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.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 &&
+ vgic_irq_is_sgi(irq->intid)) {
+ while (irq->source &&
+ count < kvm_vgic_global_state.nr_lr)
+ vgic_populate_lr(vcpu, irq, count++);
+ } else {
+ vgic_populate_lr(vcpu, irq, count++);
+ }
+
+next:
+ spin_unlock(&irq->irq_lock);
+
+ if (count == kvm_vgic_global_state.nr_lr)
+ break;
+ }
+
+out_clean:
+ vcpu->arch.vgic_cpu.used_lrs = count;
+
+ /* Nuke remaining LRs */
+ for ( ; count < kvm_vgic_global_state.nr_lr; count++)
+ vgic_clear_lr(vcpu, count);
+}
+
+/* Sync back the hardware VGIC state into our emulation after a guest's run. */
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
+{
+ vgic_process_maintenance_interrupt(vcpu);
+ vgic_fold_lr_state(vcpu);
+ vgic_prune_ap_list(vcpu);
+}
+
+/* Flush our emulation state into the GIC hardware before entering the guest. */
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+ spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+ vgic_flush_lr_state(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 c625767..29b96b9 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -16,6 +16,8 @@
#ifndef __KVM_ARM_VGIC_NEW_H__
#define __KVM_ARM_VGIC_NEW_H__
+#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
+
struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
u32 intid);
bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 17/54] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (15 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 16/54] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-05-02 12:16 ` Marc Zyngier
2016-04-28 16:45 ` [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 " Andre Przywara
` (36 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
From: Marc Zyngier <marc.zyngier@arm.com>
Processing maintenance interrupts and accessing the list registers
are dependent on the host's GIC version.
Introduce vgic-v2.c to contain GICv2 specific functions.
Implement the GICv2 specific code for syncing the emulation state
into the VGIC registers.
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>
---
Changelog RFC..v1:
- remove explicit LR_STATE clearing on maintenance interrupt handling
- improve documentation for vgic_v2_populate_lr()
- remove WARN_ON on non-edge IRQs in maintenance interrupts
- simplify multi-CPU source SGI handling
Changelog v1 .. v2:
- inject the IRQ priority into the list register
include/linux/irqchip/arm-gic.h | 1 +
virt/kvm/arm/vgic/vgic-v2.c | 178 ++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 19 ++---
virt/kvm/arm/vgic/vgic.h | 6 ++
4 files changed, 194 insertions(+), 10 deletions(-)
create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 9c94026..be0d26f 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -76,6 +76,7 @@
#define GICH_LR_VIRTUALID (0x3ff << 0)
#define GICH_LR_PHYSID_CPUID_SHIFT (10)
#define GICH_LR_PHYSID_CPUID (0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
+#define GICH_LR_PRIORITY_SHIFT 23
#define GICH_LR_STATE (3 << 28)
#define GICH_LR_PENDING_BIT (1 << 28)
#define GICH_LR_ACTIVE_BIT (1 << 29)
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
new file mode 100644
index 0000000..4cee616
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -0,0 +1,178 @@
+/*
+ * 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/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, kvm_vgic_global_state.nr_lr) {
+ u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
+
+ WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
+
+ kvm_notify_acked_irq(vcpu->kvm, 0,
+ intid - VGIC_NR_PRIVATE_IRQS);
+
+ 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 (vgic_irq_is_sgi(intid)) {
+ 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 cleared in struct vgic_irq
+ * - for a level sensitive IRQ the pending state value is unchanged;
+ * it is dictated directly by the input level
+ *
+ * If @irq describes an SGI with multiple sources, we choose the
+ * lowest-numbered source VCPU and clear that bit in the source bitmap.
+ *
+ * The irq_lock must be held by the caller.
+ */
+void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
+{
+ u32 val = irq->intid;
+
+ if (irq->pending) {
+ val |= GICH_LR_PENDING_BIT;
+
+ if (irq->config == VGIC_CONFIG_EDGE)
+ irq->pending = false;
+
+ if (vgic_irq_is_sgi(irq->intid)) {
+ 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;
+ }
+
+ /* The GICv2 LR only holds five bits of priority. */
+ val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
+
+ vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
+}
+
+void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+ vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index a656a12e5..9f75685 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -397,10 +397,12 @@ retry:
static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
{
+ vgic_v2_process_maintenance(vcpu);
}
static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
{
+ vgic_v2_fold_lr_state(vcpu);
}
/* Requires the ap_list_lock and the irq_lock to be held. */
@@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
{
DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+
+ vgic_v2_populate_lr(vcpu, irq, lr);
}
static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
{
+ vgic_v2_clear_lr(vcpu, lr);
}
static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
{
+ vgic_v2_set_underflow(vcpu);
}
static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
@@ -441,14 +447,12 @@ static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
{
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
- struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
- u32 model = dist->vgic_model;
struct vgic_irq *irq;
int count = 0;
DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(vgic_cpu->ap_list_lock));
- if (unlikely(!dist->enabled))
+ if (unlikely(!vcpu->kvm->arch.vgic.enabled))
goto out_clean;
if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
@@ -466,14 +470,9 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
* If we get an SGI with multiple sources, try to get
* them in all at once.
*/
- if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
- vgic_irq_is_sgi(irq->intid)) {
- while (irq->source &&
- count < kvm_vgic_global_state.nr_lr)
- vgic_populate_lr(vcpu, irq, count++);
- } else {
+ do {
vgic_populate_lr(vcpu, irq, count++);
- }
+ } while (irq->source && count < kvm_vgic_global_state.nr_lr);
next:
spin_unlock(&irq->irq_lock);
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 29b96b9..0db490e 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
u32 intid);
bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
+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_clear_lr(struct kvm_vcpu *vcpu, int lr);
+void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+
#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (16 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 17/54] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-05-03 16:16 ` Marc Zyngier
2016-05-05 17:04 ` [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend Tom Hanson
2016-04-28 16:45 ` [PATCH v2 19/54] KVM: arm/arm64: vgic-new: Implement Andre Przywara
` (35 subsequent siblings)
53 siblings, 2 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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.
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>
---
Changelog RFC..v1:
- remove outdated comment about the dist_lock
- add WARN_ON about LR_STATE not being 0 in maintenance interrupts
Changelog v1 .. v2:
- inject the IRQ priority into the list register
include/linux/irqchip/arm-gic-v3.h | 1 +
virt/kvm/arm/vgic/vgic-v3.c | 169 +++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 25 ++++--
virt/kvm/arm/vgic/vgic.h | 29 +++++++
4 files changed, 219 insertions(+), 5 deletions(-)
create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index d5d798b..56fd2c5 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -275,6 +275,7 @@
#define ICH_LR_ACTIVE_BIT (1ULL << 63)
#define ICH_LR_PHYS_ID_SHIFT 32
#define ICH_LR_PHYS_ID_MASK (0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
+#define ICH_LR_PRIORITY_SHIFT 48
#define ICH_MISR_EOI (1 << 0)
#define ICH_MISR_U (1 << 1)
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
new file mode 100644
index 0000000..461229b
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -0,0 +1,169 @@
+/*
+ * 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, kvm_vgic_global_state.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;
+
+ WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
+
+ kvm_notify_acked_irq(vcpu->kvm, 0,
+ intid - VGIC_NR_PRIVATE_IRQS);
+
+ 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 (vgic_irq_is_sgi(intid) &&
+ 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 = irq->intid;
+
+ if (irq->pending) {
+ val |= ICH_LR_PENDING_BIT;
+
+ if (irq->config == VGIC_CONFIG_EDGE)
+ irq->pending = false;
+
+ if (vgic_irq_is_sgi(irq->intid) &&
+ 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;
+
+ val |= (u64)irq->priority << ICH_LR_PRIORITY_SHIFT;
+
+ vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
+}
+
+void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+ vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 9f75685..ae52928 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -397,12 +397,18 @@ retry:
static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
{
- vgic_v2_process_maintenance(vcpu);
+ if (kvm_vgic_global_state.type == VGIC_V2)
+ vgic_v2_process_maintenance(vcpu);
+ else
+ vgic_v3_process_maintenance(vcpu);
}
static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
{
- vgic_v2_fold_lr_state(vcpu);
+ if (kvm_vgic_global_state.type == VGIC_V2)
+ vgic_v2_fold_lr_state(vcpu);
+ else
+ vgic_v3_fold_lr_state(vcpu);
}
/* Requires the ap_list_lock and the irq_lock to be held. */
@@ -412,17 +418,26 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
- vgic_v2_populate_lr(vcpu, irq, lr);
+ if (kvm_vgic_global_state.type == VGIC_V2)
+ vgic_v2_populate_lr(vcpu, irq, lr);
+ else
+ vgic_v3_populate_lr(vcpu, irq, lr);
}
static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
{
- vgic_v2_clear_lr(vcpu, lr);
+ if (kvm_vgic_global_state.type == VGIC_V2)
+ vgic_v2_clear_lr(vcpu, lr);
+ else
+ vgic_v3_clear_lr(vcpu, lr);
}
static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
{
- vgic_v2_set_underflow(vcpu);
+ if (kvm_vgic_global_state.type == VGIC_V2)
+ vgic_v2_set_underflow(vcpu);
+ else
+ 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 0db490e..81b1a20 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -28,4 +28,33 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+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_clear_lr(struct kvm_vcpu *vcpu, int lr);
+void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+#else
+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_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+}
+
+static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
+{
+}
+#endif
+
#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 19/54] KVM: arm/arm64: vgic-new: Implement
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (17 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 " Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-05-02 12:24 ` Eric Auger
2016-04-28 16:45 ` [PATCH v2 20/54] KVM: arm/arm64: vgic-new: Add MMIO handling framework Andre Przywara
` (34 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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>
---
Changelog RFC..v1:
- return false if distributor is disabled
- add vgic_kick_vcpus() implementations
include/kvm/vgic/vgic.h | 2 ++
virt/kvm/arm/vgic/vgic.c | 40 ++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 43 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 5fae4a9..2615205 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -184,6 +184,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 ae52928..eeb766e 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -519,3 +519,43 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
vgic_flush_lr_state(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;
+
+ if (!vcpu->kvm->arch.vgic.enabled)
+ return 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;
+}
+
+void vgic_kick_vcpus(struct kvm *kvm)
+{
+ struct kvm_vcpu *vcpu;
+ int c;
+
+ /*
+ * We've injected an interrupt, time to find out who deserves
+ * a good kick...
+ */
+ kvm_for_each_vcpu(c, vcpu, kvm) {
+ if (kvm_vgic_vcpu_pending_irq(vcpu))
+ kvm_vcpu_kick(vcpu);
+ }
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 81b1a20..0c92cda 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -21,6 +21,7 @@
struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
u32 intid);
bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
+void vgic_kick_vcpus(struct kvm *kvm);
void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 20/54] KVM: arm/arm64: vgic-new: Add MMIO handling framework
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (18 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 19/54] KVM: arm/arm64: vgic-new: Implement Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 21/54] KVM: arm/arm64: vgic-new: Add GICv2 " Andre Przywara
` (33 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
From: Marc Zyngier <marc.zyngier@arm.com>
Add an MMIO handling framework to the VGIC emulation:
Each register is described by its offset, size (or number of bits per
IRQ, if applicable) and the read/write handler functions. We provide
initialization macros to describe each GIC register later easily.
Separate dispatch functions for read and write accesses are connected
to the kvm_io_bus framework and binary-search for the responsible
register handler based on the offset address within the region.
We convert the incoming data (referenced by a pointer) to the host's
endianess and use pass-by-value to hand the data over to the actual
handler functions.
The register handler prototype and the endianess conversion are
courtesy of Christoffer Dall.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- rework MMIO dispatching to use only one kvm_io_bus device
- document purpose of register region macros
- rename "this" parameter to "dev"
- change IGROUPR to be RAO (returning 1 => Group1 IRQs)
Changelog v1 .. v2:
* MASSIVE rework:
- store register_region pointer in kvm_io_bus linked struct
- replace write_mask_xxx functions with extract_bytes() implementation
- change handler functions' prototypes to take and return unsigned long
- use binary search to find matching register handler
- convert endianess of input data in dispatch_mmio_xxx functions
- improve readability of register initializer macros
- remove any GICv2/GICv3 specific functions from vgic-mmio.c
- rename file from vgic_mmio.c to vgic-mmio.c
include/kvm/vgic/vgic.h | 13 ++++
virt/kvm/arm/vgic/vgic-mmio.c | 171 ++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.h | 77 +++++++++++++++++++
3 files changed, 261 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 2615205..4ec1270 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -106,6 +106,16 @@ struct vgic_irq {
enum vgic_irq_config config; /* Level or edge */
};
+struct vgic_register_region;
+
+struct vgic_io_device {
+ gpa_t base_addr;
+ struct kvm_vcpu *redist_vcpu;
+ const struct vgic_register_region *regions;
+ int nr_regions;
+ struct kvm_io_device dev;
+};
+
struct vgic_dist {
bool in_kernel;
bool ready;
@@ -132,6 +142,9 @@ struct vgic_dist {
bool enabled;
struct vgic_irq *spis;
+
+ struct vgic_io_device dist_iodev;
+ 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..28b9cfe
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -0,0 +1,171 @@
+/*
+ * 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/bitops.h>
+#include <linux/bsearch.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/iodev.h>
+#include <kvm/vgic/vgic.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+/* extract @num bytes at @offset bytes offset in data */
+unsigned long extract_bytes(unsigned long data,
+ unsigned int offset, unsigned int num)
+{
+ return (data >> (offset * 8)) & GENMASK_ULL(num * 8 - 1, 0);
+}
+
+unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ return 0;
+}
+
+unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ return -1UL;
+}
+
+void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
+ unsigned int len, unsigned long val)
+{
+ /* Ignore */
+}
+
+static int match_region(const void *key, const void *elt)
+{
+ const unsigned int offset = (unsigned long)key;
+ const struct vgic_register_region *region = elt;
+
+ if (offset < region->reg_offset)
+ return -1;
+
+ if (offset >= region->reg_offset + region->len)
+ return 1;
+
+ return 0;
+}
+
+/* Find the proper register handler entry given a certain address offset. */
+static const struct vgic_register_region *
+vgic_find_mmio_region(const struct vgic_register_region *region, int nr_regions,
+ unsigned int offset)
+{
+ return bsearch((void *)(uintptr_t)offset, region, nr_regions,
+ sizeof(region[0]), match_region);
+}
+
+/*
+ * kvm_mmio_read_buf() returns a value in a format where it can be converted
+ * to a byte array and be directly observed as the guest wanted it to appear
+ * in memory if it had done the store itself, which is LE for the GIC, as the
+ * guest knows the GIC is always LE.
+ *
+ * We convert this value to the CPUs native format to deal with it as a data
+ * value.
+ */
+unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len)
+{
+ unsigned long data = kvm_mmio_read_buf(val, len);
+
+ switch (len) {
+ case 1:
+ return data;
+ case 2:
+ return le16_to_cpu(data);
+ case 4:
+ return le32_to_cpu(data);
+ default:
+ return le64_to_cpu(data);
+ }
+}
+
+/*
+ * kvm_mmio_write_buf() expects a value in a format such that if converted to
+ * a byte array it is observed as the guest would see it if it could perform
+ * the load directly. Since the GIC is LE, and the guest knows this, the
+ * guest expects a value in little endian format.
+ *
+ * We convert the data value from the CPUs native format to LE so that the
+ * value is returned in the proper format.
+ */
+void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
+ unsigned long data)
+{
+ switch (len) {
+ case 1:
+ break;
+ case 2:
+ data = cpu_to_le16(data);
+ break;
+ case 4:
+ data = cpu_to_le32(data);
+ break;
+ default:
+ data = cpu_to_le64(data);
+ }
+
+ kvm_mmio_write_buf(buf, len, data);
+}
+
+static
+struct vgic_io_device *kvm_to_vgic_iodev(const struct kvm_io_device *dev)
+{
+ return container_of(dev, struct vgic_io_device, dev);
+}
+
+static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+ const struct vgic_register_region *region;
+ struct kvm_vcpu *r_vcpu;
+ unsigned long data;
+
+ region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
+ addr - iodev->base_addr);
+ if (!region)
+ return -EOPNOTSUPP;
+
+ r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+ data = region->read(r_vcpu, addr, len);
+ vgic_data_host_to_mmio_bus(val, len, data);
+ return 0;
+}
+
+static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+ const struct vgic_register_region *region;
+ struct kvm_vcpu *r_vcpu;
+ unsigned long data = vgic_data_mmio_bus_to_host(val, len);
+
+ region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
+ addr - iodev->base_addr);
+ if (!region)
+ return -EOPNOTSUPP;
+
+ r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+ region->write(r_vcpu, addr, len, data);
+ return 0;
+}
+
+struct kvm_io_device_ops kvm_io_gic_ops = {
+ .read = dispatch_mmio_read,
+ .write = dispatch_mmio_write,
+};
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
new file mode 100644
index 0000000..18d3869
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -0,0 +1,77 @@
+/*
+ * 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 {
+ unsigned int reg_offset;
+ unsigned int len;
+ unsigned int bits_per_irq;
+ unsigned long (*read)(struct kvm_vcpu *vcpu, gpa_t addr,
+ unsigned int len);
+ void (*write)(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len,
+ unsigned long val);
+};
+
+extern struct kvm_io_device_ops kvm_io_gic_ops;
+
+/*
+ * Some VGIC registers store per-IRQ information, with a different number
+ * of bits per IRQ. For those registers this macro is used.
+ * The _WITH_LENGTH version instantiates registers with a fixed length
+ * and is mutually exclusive with the _PER_IRQ version.
+ */
+#define REGISTER_DESC_WITH_BITS_PER_IRQ(off, read_ops, write_ops, bpi) \
+ { \
+ .reg_offset = off, \
+ .bits_per_irq = bpi, \
+ .len = bpi * 1024 / 8, \
+ .read = read_ops, \
+ .write = write_ops, \
+ }
+
+#define REGISTER_DESC_WITH_LENGTH(off, read_ops, write_ops, length) \
+ { \
+ .reg_offset = off, \
+ .bits_per_irq = 0, \
+ .len = length, \
+ .read = read_ops, \
+ .write = write_ops, \
+ }
+
+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);
+
+unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len);
+
+void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
+ unsigned long data);
+
+unsigned long extract_bytes(unsigned long data,
+ unsigned int offset, unsigned int num);
+
+unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len);
+
+unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
+ unsigned int len, unsigned long val);
+
+#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 21/54] KVM: arm/arm64: vgic-new: Add GICv2 MMIO handling framework
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (19 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 20/54] KVM: arm/arm64: vgic-new: Add MMIO handling framework Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-05-03 15:32 ` Marc Zyngier
2016-04-28 16:45 ` [PATCH v2 22/54] KVM: arm/arm64: vgic-new: Export register access interface Andre Przywara
` (32 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
Create vgic-mmio-v2.c to describe GICv2 emulation specific handlers
using the initializer macros provided by the VGIC MMIO framework.
Provide a function to register the GICv2 distributor registers to
the kvm_io_bus framework.
The actual handler functions are still stubs in this patch.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
Changelog v1 .. v2:
- new patch, split out from the generic MMIO framework patch
- use a separate file to hold GICv2 emulation specific handlers
- replace _nyi stub functions with raz/wi versions
virt/kvm/arm/vgic/vgic-mmio-v2.c | 62 ++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.c | 26 +++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.h | 2 ++
3 files changed, 90 insertions(+)
create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v2.c
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
new file mode 100644
index 0000000..afee778
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -0,0 +1,62 @@
+/*
+ * VGICv2 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/irqchip/arm-gic.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/iodev.h>
+#include <kvm/vgic/vgic.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+static const struct vgic_register_region vgic_v2_dist_registers[] = {
+ REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
+ vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 2),
+ REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+ REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+ REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+};
+
+unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
+{
+ dev->regions = vgic_v2_dist_registers;
+ dev->nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+
+ kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
+
+ return SZ_4K;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 28b9cfe..4301da0 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -169,3 +169,29 @@ struct kvm_io_device_ops kvm_io_gic_ops = {
.read = dispatch_mmio_read,
.write = dispatch_mmio_write,
};
+
+int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
+ enum vgic_type type)
+{
+ struct vgic_io_device *io_device = &kvm->arch.vgic.dist_iodev;
+ int ret = 0;
+ unsigned int len;
+
+ switch (type) {
+ case VGIC_V2:
+ len = vgic_v2_init_dist_iodev(io_device);
+ break;
+ default:
+ BUG_ON(1);
+ }
+
+ io_device->base_addr = dist_base_address;
+ io_device->redist_vcpu = NULL;
+
+ mutex_lock(&kvm->slots_lock);
+ ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, dist_base_address,
+ len, &io_device->dev);
+ mutex_unlock(&kvm->slots_lock);
+
+ return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 18d3869..4f4dd2b 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -74,4 +74,6 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
unsigned int len, unsigned long val);
+unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
+
#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 22/54] KVM: arm/arm64: vgic-new: Export register access interface
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (20 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 21/54] KVM: arm/arm64: vgic-new: Add GICv2 " Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 23/54] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers Andre Przywara
` (31 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
From: Christoffer Dall <christoffer.dall@linaro.org>
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 provide a wrapper to plug into our MMIO framework and
find the respective register handler.
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework
- handle endianess explicitly
virt/kvm/arm/vgic/vgic-mmio-v2.c | 30 ++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 2 ++
2 files changed, 32 insertions(+)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index afee778..02814a0 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -60,3 +60,33 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
return SZ_4K;
}
+
+/*
+ * When userland tries to access the VGIC register handlers, we need to
+ * create a usable struct vgic_io_device to be passed to the handlers and we
+ * have to set up a buffer similar to what would have happened if a guest MMIO
+ * access occurred, including doing endian conversions on BE systems.
+ */
+int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *val)
+{
+ unsigned int len = 4;
+ u8 buf[4];
+ int ret;
+
+ struct vgic_io_device dev = {
+ .regions = vgic_v2_dist_registers,
+ .nr_regions = ARRAY_SIZE(vgic_v2_dist_registers),
+ };
+
+ if (is_write) {
+ vgic_data_host_to_mmio_bus(buf, len, *val);
+ ret = kvm_io_gic_ops.write(vcpu, &dev.dev, offset, len, buf);
+ } else {
+ ret = kvm_io_gic_ops.read(vcpu, &dev.dev, offset, len, buf);
+ if (!ret)
+ *val = vgic_data_mmio_bus_to_host(buf, len);
+ }
+
+ return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 0c92cda..008588b 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -28,6 +28,8 @@ 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_clear_lr(struct kvm_vcpu *vcpu, int lr);
void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *val);
#ifdef CONFIG_KVM_ARM_VGIC_V3
void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 23/54] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (21 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 22/54] KVM: arm/arm64: vgic-new: Export register access interface Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 24/54] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers Andre Przywara
` (30 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
From: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- kick VCPUs is the distributor gets enabled
- improve comment
Changelog v1 .. v2:
- adapt to new MMIO framework
- use switch() statements to improve readability
include/linux/irqchip/arm-gic.h | 1 +
virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
virt/kvm/arm/vgic/vgic.h | 3 +++
3 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index be0d26f..fd05185 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -33,6 +33,7 @@
#define GIC_DIST_CTRL 0x000
#define GIC_DIST_CTR 0x004
+#define GIC_DIST_IIDR 0x008
#define GIC_DIST_IGROUP 0x080
#define GIC_DIST_ENABLE_SET 0x100
#define GIC_DIST_ENABLE_CLEAR 0x180
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 02814a0..bf64bbf 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -20,9 +20,55 @@
#include "vgic.h"
#include "vgic-mmio.h"
+static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 value;
+
+ switch (addr & 0x0c) {
+ case GIC_DIST_CTRL:
+ value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
+ break;
+ case GIC_DIST_CTR:
+ 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 GIC_DIST_IIDR:
+ value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+ break;
+ default:
+ return 0;
+ }
+
+ return extract_bytes(value, addr & 3, len);
+}
+
+static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ switch (addr & 0x0c) {
+ case GIC_DIST_CTRL:
+ if (!(addr & 1)) {
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ bool was_enabled = dist->enabled;
+
+ dist->enabled = val & GICD_ENABLE;
+ if (!was_enabled && dist->enabled)
+ vgic_kick_vcpus(vcpu->kvm);
+ }
+ break;
+ case GIC_DIST_CTR:
+ case GIC_DIST_IIDR:
+ /* Nothing to do */
+ return;
+ }
+}
+
static const struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
+ vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 008588b..1ab7d97 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
+
#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 24/54] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (22 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 23/54] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 25/54] KVM: arm/arm64: vgic-new: Add PENDING " Andre Przywara
` (29 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
As the enable register handlers are shared between the v2 and v3
emulation, their implementation goes into vgic-mmio.c, to be easily
referenced from the v3 emulation as well later.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- use lower bits of address to determine IRQ number
- remove TODO, confirmed to be fine
Changelog v1 .. v2:
- adapt to new MMIO framework
virt/kvm/arm/vgic/vgic-mmio-v2.c | 4 +--
virt/kvm/arm/vgic/vgic-mmio.c | 56 ++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.h | 11 ++++++++
3 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index bf64bbf..d5eafe9 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+ vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+ vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 4301da0..120eb25 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
/* Ignore */
}
+/*
+ * 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.
+ */
+unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 intid = (addr & 0x7f) * 8;
+ u32 value = 0;
+ int i;
+
+ /* 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);
+ }
+
+ return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ 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_unlock(vcpu->kvm, irq);
+ }
+}
+
+void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ 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;
+
+ spin_unlock(&irq->irq_lock);
+ }
+}
+
static int match_region(const void *key, const void *elt)
{
const unsigned int offset = (unsigned long)key;
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 4f4dd2b..188909a 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -74,6 +74,17 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
unsigned int len, unsigned long val);
+unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val);
+
+void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val);
+
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 25/54] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (23 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 24/54] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 26/54] KVM: arm/arm64: vgic-new: Add ACTIVE " Andre Przywara
` (28 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
The pending register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be easily
referenced from the v3 emulation as well later.
For level triggered interrupts the real line level is unaffected by
this write, so we keep this state separate and combine it with the
device's level to get the actual pending state.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove IRQ lock from read handler
- remove TODO from clear pending handler
Changelog v1 .. v2:
- adapt to new MMIO framework
virt/kvm/arm/vgic/vgic-mmio-v2.c | 4 +--
virt/kvm/arm/vgic/vgic-mmio.c | 60 ++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.h | 12 ++++++++
3 files changed, 74 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index d5eafe9..4797203 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -76,9 +76,9 @@ static const 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_raz, vgic_mmio_write_wi, 1),
+ vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+ vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 120eb25..223cc84 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -102,6 +102,66 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
}
}
+unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 intid = (addr & 0x7f) * 8;
+ u32 value = 0;
+ int i;
+
+ /* 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->pending)
+ value |= (1U << i);
+ }
+
+ return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ 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_unlock(vcpu->kvm, irq);
+ }
+}
+
+void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ 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;
+ }
+
+ spin_unlock(&irq->irq_lock);
+ }
+}
+
static int match_region(const void *key, const void *elt)
{
const unsigned int offset = (unsigned long)key;
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 188909a..d4fc029 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -85,6 +85,18 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val);
+unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val);
+
+void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val);
+
+
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 26/54] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (24 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 25/54] KVM: arm/arm64: vgic-new: Add PENDING " Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-05-05 16:48 ` Tom Hanson
2016-04-28 16:45 ` [PATCH v2 27/54] KVM: arm/arm64: vgic-new: Add PRIORITY " Andre Przywara
` (27 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
The active register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be
easily referenced from the v3 emulation as well later.
Since activation/deactivation of an interrupt may happen entirely
in the guest without it ever exiting, we need some extra logic to
properly track the active state.
Putting it on an ap_list on activation is similar to the normal case
handled by vgic_queue_irq_unlock(), but differs in some details that
make a separate implementation worthwhile.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- handling queueing in write handler
- remove IRQ lock from read handler
Changelog v1 .. v2:
- adapt to new MMIO framework
virt/kvm/arm/vgic/vgic-mmio-v2.c | 4 +-
virt/kvm/arm/vgic/vgic-mmio.c | 120 +++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.h | 10 ++++
3 files changed, 132 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 4797203..6b58455 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -80,9 +80,9 @@ static const 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_raz, vgic_mmio_write_wi, 1),
+ vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+ vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 223cc84..74c76e5 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -162,6 +162,126 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
}
}
+unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 intid = (addr & 0x7f) * 8;
+ u32 value = 0;
+ int i;
+
+ /* 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->active)
+ value |= (1U << i);
+ }
+
+ return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ 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;
+
+ /*
+ * Christoffer wrote:
+ * 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);
+ }
+}
+
+void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ 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);
+
+ /* As this is a special case, we can't use the
+ * vgic_queue_irq_unlock() function to put this on a VCPU.
+ * So deal with this here explicitly unless the IRQs was
+ * already active, it was on a VCPU before or there is no
+ * target VCPU assigned at the moment.
+ */
+ if (irq->active || irq->vcpu || !irq->target_vcpu) {
+ irq->active = true;
+
+ spin_unlock(&irq->irq_lock);
+ continue;
+ }
+
+ spin_unlock(&irq->irq_lock);
+retry:
+ vcpu = irq->target_vcpu;
+
+ spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+ spin_lock(&irq->irq_lock);
+
+ /*
+ * Recheck after dropping the IRQ lock to see if we should
+ * still care about queueing it.
+ */
+ if (irq->active || irq->vcpu) {
+ irq->active = true;
+
+ spin_unlock(&irq->irq_lock);
+ spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+ continue;
+ }
+
+ /* Did the target VCPU change while we had the lock dropped? */
+ if (vcpu != irq->target_vcpu) {
+ spin_unlock(&irq->irq_lock);
+ spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+ goto retry;
+ }
+
+ /* Now queue the IRQ to the VCPU's ap_list. */
+ list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
+ irq->vcpu = vcpu;
+
+ irq->active = true;
+
+ spin_unlock(&irq->irq_lock);
+ spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+ kvm_vcpu_kick(vcpu);
+ }
+}
+
static int match_region(const void *key, const void *elt)
{
const unsigned int offset = (unsigned long)key;
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index d4fc029..fa875dc 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -96,6 +96,16 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val);
+unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val);
+
+void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val);
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 27/54] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (25 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 26/54] KVM: arm/arm64: vgic-new: Add ACTIVE " Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 28/54] KVM: arm/arm64: vgic-new: Add CONFIG " Andre Przywara
` (26 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
The priority register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be
easily referenced from the v3 emulation as well later.
There is a corner case when we change the priority of a pending
interrupt which we don't handle at the moment.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework
virt/kvm/arm/vgic/vgic-mmio-v2.c | 2 +-
virt/kvm/arm/vgic/vgic-mmio.c | 39 +++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.h | 7 +++++++
3 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 6b58455..78ed2ac 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -84,7 +84,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+ vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 74c76e5..ac13115 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -282,6 +282,45 @@ retry:
}
}
+unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 intid = addr & 0x3ff;
+ int i;
+ u64 val = 0;
+
+ for (i = 0; i < len; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ val |= (u64)irq->priority << (i * 8);
+ }
+
+ return val;
+}
+
+/*
+ * We currently don't handle changing the priority of an interrupt that
+ * is already pending on a VCPU. If there is a need for this, we would
+ * need to make this VCPU exit and re-evaluate the priorities, potentially
+ * leading to this interrupt getting presented now to the guest (if it has
+ * been masked by the priority mask before).
+ */
+void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = addr & 0x3ff;
+ 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->priority = (val >> (i * 8)) & 0xff;
+ spin_unlock(&irq->irq_lock);
+ }
+}
+
static int match_region(const void *key, const void *elt)
{
const unsigned int offset = (unsigned long)key;
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index fa875dc..cd04ac5 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -107,6 +107,13 @@ void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val);
+unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val);
+
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 28/54] KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (26 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 27/54] KVM: arm/arm64: vgic-new: Add PRIORITY " Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 29/54] KVM: arm/arm64: vgic-new: Add TARGET " Andre Przywara
` (25 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
The config register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be
easily referenced from the v3 emulation as well later.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework
virt/kvm/arm/vgic/vgic-mmio-v2.c | 2 +-
virt/kvm/arm/vgic/vgic-mmio.c | 46 ++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.h | 7 ++++++
3 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 78ed2ac..008a466 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -88,7 +88,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 2),
+ vgic_mmio_read_config, vgic_mmio_write_config, 2),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index ac13115..bf4278c 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -321,6 +321,52 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
}
}
+unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 intid = (addr & 0xff) * 4;
+ u32 value = 0;
+ int i;
+
+ 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));
+ }
+
+ return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = (addr & 0xff) * 4;
+ int i;
+
+ 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.
+ */
+
+ spin_lock(&irq->irq_lock);
+ if (test_bit(i * 2 + 1, &val)) {
+ irq->config = VGIC_CONFIG_EDGE;
+ } else {
+ irq->config = VGIC_CONFIG_LEVEL;
+ irq->pending = irq->line_level | irq->soft_pending;
+ }
+ spin_unlock(&irq->irq_lock);
+ }
+}
+
static int match_region(const void *key, const void *elt)
{
const unsigned int offset = (unsigned long)key;
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index cd04ac5..884eb71 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -114,6 +114,13 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val);
+unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val);
+
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 29/54] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (27 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 28/54] KVM: arm/arm64: vgic-new: Add CONFIG " Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 30/54] KVM: arm/arm64: vgic-new: Add SGIR register handler Andre Przywara
` (24 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
The target register handlers are v2 emulation specific, so their
implementation lives entirely in vgic-mmio-v2.c.
We copy the old VGIC behaviour of assigning an IRQ to the first VCPU
set in the target mask instead of making it possibly pending on
multiple VCPUs.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove runtime VCPU determination from this v2-only register
- fold in implementation of vgic_v2_irq_change_affinity()
- replace ffs() with __ffs()
Changelog v1 .. v2:
- adapt to new MMIO framework
virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 008a466..7364fd7 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
}
}
+static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 intid = addr & 0x3ff;
+ int i;
+ u64 val = 0;
+
+ for (i = 0; i < len; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ val |= (u64)irq->targets << (i * 8);
+ }
+
+ return val;
+}
+
+static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = addr & 0x3ff;
+ int i;
+
+ /* GICD_ITARGETSR[0-7] are read-only */
+ if (intid < VGIC_NR_PRIVATE_IRQS)
+ return;
+
+ for (i = 0; i < len; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i);
+ int target;
+
+ spin_lock(&irq->irq_lock);
+
+ irq->targets = (val >> (i * 8)) & 0xff;
+ target = irq->targets ? __ffs(irq->targets) : 0;
+ irq->target_vcpu = kvm_get_vcpu(vcpu->kvm, target);
+
+ spin_unlock(&irq->irq_lock);
+ }
+}
+
static const 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),
@@ -86,7 +127,7 @@ static const 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_raz, vgic_mmio_write_wi, 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] 94+ messages in thread
* [PATCH v2 30/54] KVM: arm/arm64: vgic-new: Add SGIR register handler
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (28 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 29/54] KVM: arm/arm64: vgic-new: Add TARGET " Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 31/54] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers Andre Przywara
` (23 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
Triggering an IPI via this register is v2 specific, so the
implementation lives entirely in vgic-mmio-v2.c.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- silently return on illegal TargetListFilter value (=3)
Changelog v1 .. v2:
- adapt to new MMIO framework
virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 7364fd7..bcf4b43 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
}
}
+static void vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ int nr_vcpus = atomic_read(&source_vcpu->kvm->online_vcpus);
+ int intid = val & 0xf;
+ int targets = (val >> 16) & 0xff;
+ int mode = (val >> 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 */
+ return;
+ }
+
+ 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_unlock(source_vcpu->kvm, irq);
+ }
+}
+
static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len)
{
@@ -131,7 +172,7 @@ static const 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_raz, vgic_mmio_write_wi, 4),
+ vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 31/54] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (29 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 30/54] KVM: arm/arm64: vgic-new: Add SGIR register handler Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Andre Przywara
` (22 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
As this register is v2 specific, its implementation lives entirely
in vgic-mmio-v2.c.
This register allows setting the source mask of an IPI.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove IRQ lock from read handler
- update pending bit on setting the first / clearing the last bit
- queue virtual IRQ if necessary
Changelog v1 .. v2:
- adapt to new MMIO framework
virt/kvm/arm/vgic/vgic-mmio-v2.c | 62 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 60 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index bcf4b43..ae6077e 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -148,6 +148,64 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
}
}
+static unsigned long vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 intid = addr & 0x0f;
+ int i;
+ u64 val = 0;
+
+ for (i = 0; i < len; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ val |= (u64)irq->source << (i * 8);
+ }
+ return val;
+}
+
+static void vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = addr & 0x0f;
+ 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 &= ~((val >> (i * 8)) & 0xff);
+ if (!irq->source)
+ irq->pending = false;
+
+ spin_unlock(&irq->irq_lock);
+ }
+}
+
+static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = addr & 0x0f;
+ 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 |= (val >> (i * 8)) & 0xff;
+
+ if (irq->source) {
+ irq->pending = true;
+ vgic_queue_irq_unlock(vcpu->kvm, irq);
+ } else {
+ spin_unlock(&irq->irq_lock);
+ }
+ }
+}
+
static const 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),
@@ -174,9 +232,9 @@ static const 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_raz, vgic_mmio_write_wi, 16),
+ vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+ vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
};
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (30 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 31/54] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-29 14:04 ` Vladimir Murzin
` (2 more replies)
2016-04-28 16:45 ` [PATCH v2 33/54] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers Andre Przywara
` (21 subsequent siblings)
53 siblings, 3 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
Create a new file called vgic-mmio-v3.c and describe the GICv3
distributor and redistributor registers there.
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 provide a function to deal with the registration of the two
separate redistributor frames per VCPU.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- adapt to new MMIO registration approach:
register one device for the distributor and two for each VCPU
- implement special handling for private interrupts
- remove empty stub functions
- make IGROUPR return RAO
Changelog v1 .. v2:
- adapt to new framework, introduce vgic-mmio-v3.c
- remove userland register access functions (for now)
- precompute .len when describing a VGIC register
- add missed pointer incrementation on registering redist regions
- replace _nyi stub functions with raz/wi versions
virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.c | 5 +
virt/kvm/arm/vgic/vgic-mmio.h | 2 +
virt/kvm/arm/vgic/vgic.h | 3 +
4 files changed, 201 insertions(+)
create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
new file mode 100644
index 0000000..c6765d4
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -0,0 +1,191 @@
+/*
+ * VGICv3 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/irqchip/arm-gic-v3.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/iodev.h>
+#include <kvm/vgic/vgic.h>
+
+#include <asm/kvm_emulate.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+/*
+ * 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(off, read_ops, write_ops, bpi) \
+ { \
+ .reg_offset = off, \
+ .bits_per_irq = bpi, \
+ .len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
+ .read = vgic_mmio_read_raz, \
+ .write = vgic_mmio_write_wi, \
+ }, { \
+ .reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
+ .bits_per_irq = bpi, \
+ .len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8, \
+ .read = read_ops, \
+ .write = write_ops, \
+ }
+
+static const struct vgic_register_region vgic_v3_dist_registers[] = {
+ REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+ REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
+ vgic_mmio_read_rao, 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),
+ REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
+ REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+};
+
+static const struct vgic_register_region vgic_v3_redist_registers[] = {
+ REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+ REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+ REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+ REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+ REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+ REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+};
+
+static const struct vgic_register_region vgic_v3_private_registers[] = {
+ REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
+ vgic_mmio_read_rao, 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),
+};
+
+unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
+{
+ dev->regions = vgic_v3_dist_registers;
+ dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
+
+ kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
+
+ return SZ_64K;
+}
+
+int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
+{
+ int nr_vcpus = atomic_read(&kvm->online_vcpus);
+ struct kvm_vcpu *vcpu;
+ struct vgic_io_device *devices, *device;
+ int c, ret = 0;
+
+ devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
+ GFP_KERNEL);
+ if (!devices)
+ return -ENOMEM;
+
+ device = devices;
+ kvm_for_each_vcpu(c, vcpu, kvm) {
+ kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
+ device->base_addr = redist_base_address;
+ device->regions = vgic_v3_redist_registers;
+ device->nr_regions = ARRAY_SIZE(vgic_v3_redist_registers);
+ device->redist_vcpu = vcpu;
+
+ mutex_lock(&kvm->slots_lock);
+ ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+ redist_base_address,
+ SZ_64K, &device->dev);
+ mutex_unlock(&kvm->slots_lock);
+
+ if (ret)
+ break;
+
+ device++;
+ kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
+ device->base_addr = redist_base_address + SZ_64K;
+ device->regions = vgic_v3_private_registers;
+ device->nr_regions = ARRAY_SIZE(vgic_v3_private_registers);
+ device->redist_vcpu = vcpu;
+
+ mutex_lock(&kvm->slots_lock);
+ ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+ redist_base_address + SZ_64K,
+ SZ_64K, &device->dev);
+ mutex_unlock(&kvm->slots_lock);
+ if (ret) {
+ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+ &devices[c * 2].dev);
+ break;
+ }
+ device++;
+ redist_base_address += 2 * SZ_64K;
+ }
+
+ if (ret) {
+ for (c--; c >= 0; c--) {
+ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+ &devices[c * 2].dev);
+ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+ &devices[c * 2 + 1].dev);
+ }
+ kfree(devices);
+ } else {
+ kvm->arch.vgic.redist_iodevs = devices;
+ }
+
+ return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index bf4278c..80d977e 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -502,6 +502,11 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
case VGIC_V2:
len = vgic_v2_init_dist_iodev(io_device);
break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+ case VGIC_V3:
+ len = vgic_v3_init_dist_iodev(io_device);
+ break;
+#endif
default:
BUG_ON(1);
}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 884eb71..3585ac6 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -123,4 +123,6 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
+unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
+
#endif
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 1ab7d97..6fe07df 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -61,6 +61,9 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
{
}
+
#endif
+void kvm_register_vgic_device(unsigned long type);
+
#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 33/54] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (31 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 34/54] KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and TYPER handler Andre Przywara
` (20 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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>
---
Changelog RFC..v1:
- kick VCPUs if distributor gets enabled
Changelog v1 .. v2:
- rewrite write handler to use switch statement
virt/kvm/arm/vgic/vgic-mmio-v3.c | 50 +++++++++++++++++++++++++++++++++++++++-
virt/kvm/arm/vgic/vgic.h | 2 ++
2 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index c6765d4..64c0a8f 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -22,6 +22,54 @@
#include "vgic.h"
#include "vgic-mmio.h"
+static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 value = 0;
+
+ switch (addr & 0x0c) {
+ 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;
+ }
+
+ return extract_bytes(value, addr & 3, len);
+}
+
+static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ switch (addr & 0x0c) {
+ case GICD_CTLR:
+ if (!(addr & 1)) {
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ bool was_enabled = dist->enabled;
+
+ dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
+
+ if (!was_enabled && dist->enabled)
+ vgic_kick_vcpus(vcpu->kvm);
+ }
+ break;
+ case GICD_TYPER:
+ case GICD_IIDR:
+ return;
+ }
+}
+
/*
* The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
* redistributors, while SPIs are covered by registers in the distributor
@@ -46,7 +94,7 @@
static const struct vgic_register_region vgic_v3_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+ vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 6fe07df..86e9830 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
+
#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 34/54] KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and TYPER handler
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (32 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 33/54] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 35/54] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler Andre Przywara
` (19 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
The redistributor TYPER tells the OS about the associated MPIDR,
also the LAST bit is crucial to determine the number of redistributors.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework
virt/kvm/arm/vgic/vgic-mmio-v3.c | 44 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 64c0a8f..5029281 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -71,6 +71,46 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
}
/*
+ * 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 unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ unsigned long mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
+ int target_vcpu_id = 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;
+
+ return extract_bytes(value, addr & 7, len);
+}
+
+static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 value;
+
+ value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+ return extract_bytes(value, addr & 3, len);
+}
+
+/*
* 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.
@@ -127,9 +167,9 @@ static const struct vgic_register_region vgic_v3_redist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+ vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+ vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8),
REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 35/54] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (33 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 34/54] KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and TYPER handler Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 36/54] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers Andre Przywara
` (18 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
We implement the only one ID register that is required by the
architecture, also this is the one that Linux actually checks.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework
virt/kvm/arm/vgic/vgic-mmio-v3.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 5029281..e6f2607 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -110,6 +110,22 @@ static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
return extract_bytes(value, addr & 3, len);
}
+static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 regnr = (addr & 0x3f) - (GICD_IDREGS & 0x3f);
+ u32 reg = 0;
+
+ switch (regnr + GICD_IDREGS) {
+ case GICD_PIDR2:
+ /* report a GICv3 compliant implementation */
+ reg = 0x3b;
+ break;
+ }
+
+ return extract_bytes(reg, addr & 3, len);
+}
+
/*
* The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
* redistributors, while SPIs are covered by registers in the distributor
@@ -160,7 +176,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+ vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
};
static const struct vgic_register_region vgic_v3_redist_registers[] = {
@@ -175,7 +191,7 @@ static const struct vgic_register_region vgic_v3_redist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+ vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
};
static const struct vgic_register_region vgic_v3_private_registers[] = {
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 36/54] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (34 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 35/54] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 37/54] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler Andre Przywara
` (17 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 UTC (permalink / raw)
To: linux-arm-kernel
Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
register can handle, the new IROUTER register covers the whole range
of possible target (V)CPUs by using the same MPIDR that the cores
report themselves.
In addition to translating this MPIDR into a vcpu pointer we store
the originally written value as well. The architecture allows to
write any values into the register, which must be read back as written.
Since we don't support affinity level 3, we don't need to take care
about the upper word of this 64-bit register, which simplifies the
handling a bit.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- fold in and simplify vgic_v3_irq_change_affinity
Changelog v1 .. v2:
- adapt to new MMIO framework
virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 64 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index e6f2607..09c0324 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -86,6 +86,69 @@ 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 unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ int intid = (addr & 0x1fff) / 8;
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+ unsigned long mpidr;
+
+ if (!irq)
+ return 0;
+
+ mpidr = decompress_mpidr(irq->mpidr);
+ return extract_bytes(mpidr, addr & 7, len);
+}
+
+static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ int intid = (addr & 0x1fff) / 8;
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+ unsigned long mask = 0xffffffff; /* upper word is WI */
+ u64 mpidr;
+
+ if (!irq)
+ return;
+
+ /*
+ * There are only two supported options:
+ * (1) aligned 64-bit access
+ * (2) aligned 32-bit access
+ *
+ * TODO: make this check generic and move it to dispatch_...()
+ */
+ if (len != 4 && len != 8)
+ return;
+
+
+ /* The upper word is WI for us since we don't implement Aff3. */
+ if (addr & 4)
+ return;
+
+ spin_lock(&irq->irq_lock);
+
+ mpidr = decompress_mpidr(irq->mpidr);
+ mpidr = (mpidr & ~mask) | (val & mask);
+ irq->mpidr = compress_mpidr(mpidr);
+ irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
+
+ spin_unlock(&irq->irq_lock);
+}
+
static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len)
{
@@ -174,7 +237,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
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_raz, vgic_mmio_write_wi, 64),
+ 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] 94+ messages in thread
* [PATCH v2 37/54] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (35 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 36/54] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 38/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration Andre Przywara
` (16 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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>
---
Changelog RFC..v1:
- add comment about SGI_AFFINITY_LEVEL macro
include/kvm/vgic/vgic.h | 8 +++
virt/kvm/arm/vgic/vgic-mmio-v3.c | 106 +++++++++++++++++++++++++++++++++++++++
2 files changed, 114 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 4ec1270..2c43eb8 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -209,6 +209,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-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 09c0324..786250a 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -356,3 +356,109 @@ int vgic_register_redist_iodevs(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;
+}
+
+/*
+ * The ICC_SGI* registers encode the affinity differently from the MPIDR,
+ * so provide a wrapper to use the existing defines to isolate a certain
+ * affinity level.
+ */
+#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 its 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_unlock(vcpu->kvm, irq);
+ }
+}
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 38/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (36 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 37/54] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 39/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS Andre Przywara
` (15 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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>
---
Changelog v1 .. v2:
- rename vgic_kvm_device.c to vgic-kvm-device.c
virt/kvm/arm/vgic/vgic-kvm-device.c | 108 ++++++++++++++++++++++++++++++++++++
1 file changed, 108 insertions(+)
create mode 100644 virt/kvm/arm/vgic/vgic-kvm-device.c
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] 94+ messages in thread
* [PATCH v2 39/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (37 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 38/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 40/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL Andre Przywara
` (14 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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] 94+ messages in thread
* [PATCH v2 40/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (38 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 39/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS Andre Przywara
@ 2016-04-28 16:45 ` Andre Przywara
2016-04-28 16:46 ` [PATCH v2 41/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR Andre Przywara
` (13 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:45 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] 94+ messages in thread
* [PATCH v2 41/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (39 preceding siblings ...)
2016-04-28 16:45 ` [PATCH v2 40/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-04-28 16:46 ` [PATCH v2 42/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers Andre Przywara
` (12 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 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] 94+ messages in thread
* [PATCH v2 42/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (40 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 41/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-05-03 9:59 ` Marc Zyngier
2016-04-28 16:46 ` [PATCH v2 43/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr Andre Przywara
` (11 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 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-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
virt/kvm/arm/vgic/vgic-mmio-v2.c | 34 ++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 86 insertions(+), 2 deletions(-)
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, ®, 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, ®, 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-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index ae6077e..f2a8efe 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -276,3 +276,37 @@ int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
return ret;
}
+
+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;
+ const 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;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 86e9830..e8f8dbf 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -35,6 +35,7 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
int offset, u32 *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_process_maintenance(struct kvm_vcpu *vcpu);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 43/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (41 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 42/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-04-28 16:46 ` [PATCH v2 44/54] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers Andre Przywara
` (10 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 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-kvm-device.c | 112 ++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 3 +
3 files changed, 117 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2c43eb8..73cab36 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -194,6 +194,8 @@ struct vgic_cpu {
u64 live_lrs;
};
+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-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)
{
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index e8f8dbf..a048a2b 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
#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 44/54] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (42 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 43/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-04-28 16:46 ` [PATCH v2 45/54] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors Andre Przywara
` (9 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 UTC (permalink / raw)
To: linux-arm-kernel
Userland may want to save and restore the state of the in-kernel VGIC,
so we provide the code which takes a userland request and translate
that into calls to our MMIO framework.
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..38260ae 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_uaccess(vcpu, is_write, addr, 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] 94+ messages in thread
* [PATCH v2 45/54] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (43 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 44/54] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-04-28 16:46 ` [PATCH v2 46/54] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access Andre Przywara
` (8 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 UTC (permalink / raw)
To: linux-arm-kernel
Since the GIC CPU interface is always virtualized by the hardware,
we don't have CPU interface state information readily available in our
emulation if userland wants to save or restore it.
Fortunately the GIC hypervisor interface provides the VMCR register to
access the required virtual CPU interface bits.
Provide wrappers for GICv2 and GICv3 hosts to have access to this
register.
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 | 17 +++++++++++++++++
5 files changed, 91 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 73cab36..cfc3640 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -171,6 +171,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 4cee616..70cac63 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -176,3 +176,32 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
{
vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
}
+
+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;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 461229b..2c55bd5 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -167,3 +167,25 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
{
vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
}
+
+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 eeb766e..763475d 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -440,6 +440,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 a048a2b..ea72f32 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -39,6 +39,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
int offset, u32 *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_process_maintenance(struct kvm_vcpu *vcpu);
@@ -46,6 +48,8 @@ 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_clear_lr(struct kvm_vcpu *vcpu, int lr);
void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+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_process_maintenance(struct kvm_vcpu *vcpu)
{
@@ -68,8 +72,21 @@ static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
{
}
+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] 94+ messages in thread
* [PATCH v2 46/54] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (44 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 45/54] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-05-03 10:21 ` Marc Zyngier
2016-04-28 16:46 ` [PATCH v2 47/54] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init Andre Przywara
` (7 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 UTC (permalink / raw)
To: linux-arm-kernel
Using the VMCR accessors we provide access to GIC CPU interface state
to userland by wiring it up to the existing userland interface.
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 38260ae..eaf5c1d 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_uaccess(vcpu, is_write, addr, reg);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 47/54] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (45 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 46/54] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-05-03 15:02 ` Marc Zyngier
2016-05-03 15:35 ` Marc Zyngier
2016-04-28 16:46 ` [PATCH v2 48/54] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create Andre Przywara
` (6 subsequent siblings)
53 siblings, 2 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 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>
---
Changelog v1 .. v2:
- rename vgic_init.c to vgic-init.c
include/kvm/vgic/vgic.h | 1 +
virt/kvm/arm/vgic/vgic-init.c | 122 ++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v2.c | 90 +++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v3.c | 74 +++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 6 +++
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 cfc3640..d144e3d 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -202,6 +202,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-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;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 70cac63..00dc166 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"
@@ -205,3 +210,88 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
vmcrp->pmr = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
GICH_VMCR_PRIMASK_SHIFT;
}
+
+/**
+ * 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 2c55bd5..a2026c2 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;
@@ -189,3 +197,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 ea72f32..d6fe7b4 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -41,6 +41,7 @@ int vgic_v2_dist_uaccess(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_process_maintenance(struct kvm_vcpu *vcpu);
@@ -50,6 +51,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
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_process_maintenance(struct kvm_vcpu *vcpu)
{
@@ -82,6 +84,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);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 48/54] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (46 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 47/54] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-04-28 16:46 ` [PATCH v2 49/54] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init Andre Przywara
` (5 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 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 d144e3d..899b7b7 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -202,6 +202,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] 94+ messages in thread
* [PATCH v2 49/54] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (47 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 48/54] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-04-28 16:46 ` [PATCH v2 50/54] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources Andre Przywara
` (4 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 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 early_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>
---
Changelog RFC..v1:
- initialize v2/v3 default CPU affinities explicitly
Changelog v1 .. v2:
- move lazy_init() into vgic_update_irq_pending()
include/kvm/vgic/vgic.h | 7 +-
virt/kvm/arm/vgic/vgic-init.c | 213 ++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v2.c | 5 +
virt/kvm/arm/vgic/vgic-v3.c | 5 +
virt/kvm/arm/vgic/vgic.c | 4 +
virt/kvm/arm/vgic/vgic.h | 8 ++
6 files changed, 241 insertions(+), 1 deletion(-)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 899b7b7..538078a 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -119,6 +119,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;
@@ -202,7 +203,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,
@@ -211,7 +216,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-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 80bf283..ecc1f6c 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,183 @@ 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;
+ struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
+ 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;
+ irq->target_vcpu = vcpu0;
+ if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
+ irq->targets = 0;
+ else
+ irq->mpidr = 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);
+
+ /*
+ * 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 (vgic_irq_is_sgi(i)) {
+ /* 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->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);
+}
+
+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)
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 00dc166..2c76716 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -211,6 +211,11 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
GICH_VMCR_PRIMASK_SHIFT;
}
+/* 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 a2026c2..c8c022a 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -198,6 +198,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 763475d..970e19a 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -255,6 +255,10 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
trace_vgic_update_irq_pending(cpuid, intid, level);
+ ret = vgic_lazy_init(kvm);
+ if (ret)
+ return ret;
+
vcpu = kvm_get_vcpu(kvm, cpuid);
if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
return -EINVAL;
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index d6fe7b4..444210f 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -41,6 +41,7 @@ int vgic_v2_dist_uaccess(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
@@ -51,6 +52,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
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_process_maintenance(struct kvm_vcpu *vcpu)
@@ -84,6 +86,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;
@@ -93,6 +99,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
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 50/54] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (48 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 49/54] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-05-03 10:47 ` Marc Zyngier
2016-04-28 16:46 ` [PATCH v2 51/54] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable Andre Przywara
` (3 subsequent siblings)
53 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 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-init.c | 27 +++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v2.c | 47 +++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v3.c | 44 ++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 16 +++++++++++++++
5 files changed, 135 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 538078a..07c3011 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -208,6 +208,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-init.c b/virt/kvm/arm/vgic/vgic-init.c
index ecc1f6c..27b21c4 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -321,6 +321,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)
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 2c76716..039849d 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -216,6 +216,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_iodev(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 c8c022a..1832bb0 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -203,6 +203,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_iodev(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_iodevs(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 444210f..f970e3e 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -43,6 +43,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_iodev(struct kvm *kvm, gpa_t dist_base_address,
+ enum vgic_type);
#ifdef CONFIG_KVM_ARM_VGIC_V3
void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
@@ -54,6 +57,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_iodevs(struct kvm *kvm, gpa_t dist_base_address);
#else
static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
{
@@ -94,6 +99,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_iodevs(struct kvm *kvm,
+ gpa_t dist_base_address)
+{
+ return -ENODEV;
+}
#endif
void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 51/54] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (49 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 50/54] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-04-28 16:46 ` [PATCH v2 52/54] KVM: arm/arm64: vgic-new: Wire up irqfd injection Andre Przywara
` (2 subsequent siblings)
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 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 039849d..b8bfece 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -211,9 +211,18 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
GICH_VMCR_PRIMASK_SHIFT;
}
-/* 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 1832bb0..e975a33 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -198,9 +198,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] 94+ messages in thread
* [PATCH v2 52/54] KVM: arm/arm64: vgic-new: Wire up irqfd injection
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (50 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 51/54] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-04-28 16:46 ` [PATCH v2 53/54] KVM: arm/arm64: vgic-new: implement mapped IRQ handling Andre Przywara
2016-04-28 16:46 ` [PATCH v2 54/54] KVM: arm/arm64: vgic-new: enable build Andre Przywara
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 UTC (permalink / raw)
To: linux-arm-kernel
Connect to the new VGIC to the irqfd framework, so that we can
inject IRQs.
GSI routing and MSI routing is not yet implemented.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
virt/kvm/arm/vgic/vgic-irqfd.c | 52 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 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..c675513
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-irqfd.c
@@ -0,0 +1,52 @@
+/*
+ * 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 int irqchip,
+ unsigned int 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] 94+ messages in thread
* [PATCH v2 53/54] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (51 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 52/54] KVM: arm/arm64: vgic-new: Wire up irqfd injection Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
2016-04-28 16:46 ` [PATCH v2 54/54] KVM: arm/arm64: vgic-new: enable build Andre Przywara
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 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 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>
---
Changelog RFC..v1:
- adapt to new arch_timer mapped IRQ interface
- implement inject_mapped_irq() as a macro (since it is identical to
the "un-mapped" IRQ implementation)
Changelog v1 .. v2:
- replace inject_mapped_irq() macro with a separate implementation,
which only allows mapped IRQs to be injected via this interface
include/kvm/vgic/vgic.h | 5 +++++
virt/kvm/arm/vgic/vgic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 07c3011..64aca0c 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -213,6 +213,11 @@ 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);
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq);
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
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 970e19a..5f21742 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -310,6 +310,44 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
}
+int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+ bool level)
+{
+ return vgic_update_irq_pending(kvm, cpuid, intid, level, true);
+}
+
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq)
+{
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+
+ BUG_ON(!irq);
+
+ spin_lock(&irq->irq_lock);
+
+ irq->hw = true;
+ irq->hwintid = phys_irq;
+
+ spin_unlock(&irq->irq_lock);
+
+ return 0;
+}
+
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
+{
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+
+ BUG_ON(!irq);
+
+ spin_lock(&irq->irq_lock);
+
+ irq->hw = false;
+ irq->hwintid = 0;
+
+ spin_unlock(&irq->irq_lock);
+
+ return 0;
+}
+
/**
* vgic_prune_ap_list - Remove non-relevant interrupts from the list
*
@@ -579,3 +617,15 @@ void vgic_kick_vcpus(struct kvm *kvm)
kvm_vcpu_kick(vcpu);
}
}
+
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
+{
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+ 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] 94+ messages in thread
* [PATCH v2 54/54] KVM: arm/arm64: vgic-new: enable build
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (52 preceding siblings ...)
2016-04-28 16:46 ` [PATCH v2 53/54] KVM: arm/arm64: vgic-new: implement mapped IRQ handling Andre Przywara
@ 2016-04-28 16:46 ` Andre Przywara
53 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-04-28 16:46 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>
---
Changelog v1 .. v2:
- adjust the changed filenames in the Makefiles
- add vgic-mmio-v2.c and vgic-mmio-v3.c to the Makefiles
arch/arm/kvm/Kconfig | 7 +++++++
arch/arm/kvm/Makefile | 11 +++++++++++
arch/arm64/kvm/Kconfig | 7 +++++++
arch/arm64/kvm/Makefile | 12 ++++++++++++
virt/kvm/arm/hyp/vgic-v2-sr.c | 5 +++++
5 files changed, 42 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..a596b58 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -21,7 +21,18 @@ 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-mmio-v2.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..a7a958c 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -20,10 +20,22 @@ 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-mmio-v2.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.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
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index caac41f..a3f12b3 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -21,7 +21,12 @@
#include <asm/kvm_hyp.h>
+#ifdef CONFIG_KVM_NEW_VGIC
+extern struct vgic_global kvm_vgic_global_state;
+#define vgic_v2_params kvm_vgic_global_state
+#else
extern struct vgic_params vgic_v2_params;
+#endif
static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
void __iomem *base)
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
2016-04-28 16:45 ` [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Andre Przywara
@ 2016-04-29 14:04 ` Vladimir Murzin
2016-04-29 14:22 ` Vladimir Murzin
2016-05-02 16:13 ` Eric Auger
2016-05-03 15:34 ` Marc Zyngier
2 siblings, 1 reply; 94+ messages in thread
From: Vladimir Murzin @ 2016-04-29 14:04 UTC (permalink / raw)
To: linux-arm-kernel
Hi Andre,
On 28/04/16 17:45, Andre Przywara wrote:
> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
> +{
> + int nr_vcpus = atomic_read(&kvm->online_vcpus);
> + struct kvm_vcpu *vcpu;
> + struct vgic_io_device *devices, *device;
> + int c, ret = 0;
> +
> + devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
> + GFP_KERNEL);
> + if (!devices)
> + return -ENOMEM;
> +
> + device = devices;
> + kvm_for_each_vcpu(c, vcpu, kvm) {
> + kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> + device->base_addr = redist_base_address;
> + device->regions = vgic_v3_redist_registers;
> + device->nr_regions = ARRAY_SIZE(vgic_v3_redist_registers);
> + device->redist_vcpu = vcpu;
> +
> + mutex_lock(&kvm->slots_lock);
> + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> + redist_base_address,
> + SZ_64K, &device->dev);
> + mutex_unlock(&kvm->slots_lock);
> +
> + if (ret)
> + break;
> +
> + device++;
> + kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> + device->base_addr = redist_base_address + SZ_64K;
> + device->regions = vgic_v3_private_registers;
> + device->nr_regions = ARRAY_SIZE(vgic_v3_private_registers);
> + device->redist_vcpu = vcpu;
> +
> + mutex_lock(&kvm->slots_lock);
> + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> + redist_base_address + SZ_64K,
> + SZ_64K, &device->dev);
> + mutex_unlock(&kvm->slots_lock);
> + if (ret) {
> + kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> + &devices[c * 2].dev);
> + break;
> + }
> + device++;
> + redist_base_address += 2 * SZ_64K;
> + }
Can we put cond_resched() somewhere in kvm_for_each_vcpu to avoid
complains with CONFIG_PREEMPT_NONE=y and many many cpus been used?
> # lkvm run -k gic-test.flat.a64 -m 316 -c 255 --name guest-727
> Info: Loaded kernel to 0x80080000 (69624 bytes)
> Info: Placing fdt at 0x8fe00000 - 0x8fffffff
> # Warning: The maximum recommended amount of VCPUs is 4
> Info: virtio-mmio.devices=0x200 at 0x10000:36
>
> Info: virtio-mmio.devices=0x200 at 0x10200:37
>
> Info: virtio-mmio.devices=0x200 at 0x10400:38
>
> Info: virtio-mmio.devices=0x200 at 0x10600:39
>
> INFO: rcu_sched self-detected stall on CPU
> 0-...: (5249 ticks this GP) idle=589/140000000000001/0 softirq=393/393 fqs=5244
> (t=5250 jiffies g=-166 c=-167 q=0)
> Task dump for CPU 0:
> kvm-vcpu-0 R running task 0 735 1 0x00000002
> Call trace:
> [<ffffff8008088cc4>] dump_backtrace+0x0/0x194
> [<ffffff8008088e6c>] show_stack+0x14/0x1c
> [<ffffff80080d4dd0>] sched_show_task+0xa4/0xe8
> [<ffffff80080d6ddc>] dump_cpu_task+0x40/0x4c
> [<ffffff80080fd398>] rcu_dump_cpu_stacks+0xa8/0xdc
> [<ffffff8008100214>] rcu_check_callbacks+0x28c/0x7a4
> [<ffffff80081034a8>] update_process_times+0x3c/0x68
> [<ffffff8008111820>] tick_sched_handle.isra.15+0x50/0x60
> [<ffffff8008111874>] tick_sched_timer+0x44/0x7c
> [<ffffff8008103bf8>] __hrtimer_run_queues+0xc8/0x150
> [<ffffff8008104110>] hrtimer_interrupt+0x9c/0x1b0
> [<ffffff80083b8b74>] arch_timer_handler_phys+0x2c/0x38
> [<ffffff80080f6d14>] handle_percpu_devid_irq+0x78/0x98
> [<ffffff80080f2a2c>] generic_handle_irq+0x24/0x38
> [<ffffff80080f2d98>] __handle_domain_irq+0x84/0xa8
> [<ffffff80080825e0>] gic_handle_irq+0x74/0x178
> Exception stack(0xffffffc0173e3830 to 0xffffffc0173e3950)
> 3820: ffffffc0165ac038 ffffffc0165ac080
> 3840: 0000000000000018 0000000000000004 0000000000000014 000000000000003f
> 3860: ffffffc0165aeea8 ffffffc000010000 ffffffc017ef5af0 ffffffc0173ecd28
> 3880: 000000003fef0000 cfdfdfdf00010000 ffffffc0173ecd50 000000003ff00000
> 38a0: cfdfdfdf00010000 0000000000000000 ffffff80081acaf0 0000000000000000
> 38c0: 0000000000000000 00000000000000f0 ffffffc0165ac008 0000000000000018
> 38e0: ffffff80080992e8 0000000000000078 ffffff8008276b54 0000000000002970
> 3900: 0000000000000018 ffffffc0165ac080 ffffffc0165ac038 ffffffc0173e3950
> 3920: ffffff8008276d8c ffffffc0173e3950 ffffff8008276b58 0000000020000145
> 3940: 0000000000000000 0000000000000001
> [<ffffff8008084f20>] el1_irq+0xa0/0x100
> [<ffffff8008276b58>] generic_swap+0x4/0x28
> [<ffffff800809e108>] kvm_io_bus_register_dev+0xc8/0x110
> [<ffffff80080ab054>] vgic_register_redist_iodevs+0xd8/0x20c
> [<ffffff80080a98f8>] vgic_v3_map_resources+0x98/0xec
> [<ffffff80080a8cd8>] kvm_vgic_map_resources+0x4c/0x6c
> [<ffffff80080a06d4>] kvm_arch_vcpu_ioctl_run+0x68/0x424
> [<ffffff800809bc98>] kvm_vcpu_ioctl+0x1b4/0x6f8
> [<ffffff80081aca98>] do_vfs_ioctl+0x708/0x760
> [<ffffff80081acb4c>] SyS_ioctl+0x5c/0x8c
> [<ffffff8008085630>] el0_svc_naked+0x24/0x28
Cheers
Vladimir
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
2016-04-29 14:04 ` Vladimir Murzin
@ 2016-04-29 14:22 ` Vladimir Murzin
2016-05-02 8:38 ` Christoffer Dall
0 siblings, 1 reply; 94+ messages in thread
From: Vladimir Murzin @ 2016-04-29 14:22 UTC (permalink / raw)
To: linux-arm-kernel
On 29/04/16 15:04, Vladimir Murzin wrote:
> Hi Andre,
>
> On 28/04/16 17:45, Andre Przywara wrote:
>> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>> +{
>> + int nr_vcpus = atomic_read(&kvm->online_vcpus);
>> + struct kvm_vcpu *vcpu;
>> + struct vgic_io_device *devices, *device;
>> + int c, ret = 0;
>> +
>> + devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
>> + GFP_KERNEL);
>> + if (!devices)
>> + return -ENOMEM;
>> +
>> + device = devices;
>> + kvm_for_each_vcpu(c, vcpu, kvm) {
>> + kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> + device->base_addr = redist_base_address;
>> + device->regions = vgic_v3_redist_registers;
>> + device->nr_regions = ARRAY_SIZE(vgic_v3_redist_registers);
>> + device->redist_vcpu = vcpu;
>> +
>> + mutex_lock(&kvm->slots_lock);
>> + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> + redist_base_address,
>> + SZ_64K, &device->dev);
>> + mutex_unlock(&kvm->slots_lock);
>> +
>> + if (ret)
>> + break;
>> +
>> + device++;
>> + kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> + device->base_addr = redist_base_address + SZ_64K;
>> + device->regions = vgic_v3_private_registers;
>> + device->nr_regions = ARRAY_SIZE(vgic_v3_private_registers);
>> + device->redist_vcpu = vcpu;
>> +
>> + mutex_lock(&kvm->slots_lock);
>> + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> + redist_base_address + SZ_64K,
>> + SZ_64K, &device->dev);
>> + mutex_unlock(&kvm->slots_lock);
>> + if (ret) {
>> + kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> + &devices[c * 2].dev);
>> + break;
>> + }
>> + device++;
>> + redist_base_address += 2 * SZ_64K;
>> + }
>
> Can we put cond_resched() somewhere in kvm_for_each_vcpu to avoid
Apologies, it seems to come from kvm_io_bus infrastructure.
Vladimir
> complains with CONFIG_PREEMPT_NONE=y and many many cpus been used?
>
>> # lkvm run -k gic-test.flat.a64 -m 316 -c 255 --name guest-727
>> Info: Loaded kernel to 0x80080000 (69624 bytes)
>> Info: Placing fdt at 0x8fe00000 - 0x8fffffff
>> # Warning: The maximum recommended amount of VCPUs is 4
>> Info: virtio-mmio.devices=0x200 at 0x10000:36
>>
>> Info: virtio-mmio.devices=0x200 at 0x10200:37
>>
>> Info: virtio-mmio.devices=0x200 at 0x10400:38
>>
>> Info: virtio-mmio.devices=0x200 at 0x10600:39
>>
>> INFO: rcu_sched self-detected stall on CPU
>> 0-...: (5249 ticks this GP) idle=589/140000000000001/0 softirq=393/393 fqs=5244
>> (t=5250 jiffies g=-166 c=-167 q=0)
>> Task dump for CPU 0:
>> kvm-vcpu-0 R running task 0 735 1 0x00000002
>> Call trace:
>> [<ffffff8008088cc4>] dump_backtrace+0x0/0x194
>> [<ffffff8008088e6c>] show_stack+0x14/0x1c
>> [<ffffff80080d4dd0>] sched_show_task+0xa4/0xe8
>> [<ffffff80080d6ddc>] dump_cpu_task+0x40/0x4c
>> [<ffffff80080fd398>] rcu_dump_cpu_stacks+0xa8/0xdc
>> [<ffffff8008100214>] rcu_check_callbacks+0x28c/0x7a4
>> [<ffffff80081034a8>] update_process_times+0x3c/0x68
>> [<ffffff8008111820>] tick_sched_handle.isra.15+0x50/0x60
>> [<ffffff8008111874>] tick_sched_timer+0x44/0x7c
>> [<ffffff8008103bf8>] __hrtimer_run_queues+0xc8/0x150
>> [<ffffff8008104110>] hrtimer_interrupt+0x9c/0x1b0
>> [<ffffff80083b8b74>] arch_timer_handler_phys+0x2c/0x38
>> [<ffffff80080f6d14>] handle_percpu_devid_irq+0x78/0x98
>> [<ffffff80080f2a2c>] generic_handle_irq+0x24/0x38
>> [<ffffff80080f2d98>] __handle_domain_irq+0x84/0xa8
>> [<ffffff80080825e0>] gic_handle_irq+0x74/0x178
>> Exception stack(0xffffffc0173e3830 to 0xffffffc0173e3950)
>> 3820: ffffffc0165ac038 ffffffc0165ac080
>> 3840: 0000000000000018 0000000000000004 0000000000000014 000000000000003f
>> 3860: ffffffc0165aeea8 ffffffc000010000 ffffffc017ef5af0 ffffffc0173ecd28
>> 3880: 000000003fef0000 cfdfdfdf00010000 ffffffc0173ecd50 000000003ff00000
>> 38a0: cfdfdfdf00010000 0000000000000000 ffffff80081acaf0 0000000000000000
>> 38c0: 0000000000000000 00000000000000f0 ffffffc0165ac008 0000000000000018
>> 38e0: ffffff80080992e8 0000000000000078 ffffff8008276b54 0000000000002970
>> 3900: 0000000000000018 ffffffc0165ac080 ffffffc0165ac038 ffffffc0173e3950
>> 3920: ffffff8008276d8c ffffffc0173e3950 ffffff8008276b58 0000000020000145
>> 3940: 0000000000000000 0000000000000001
>> [<ffffff8008084f20>] el1_irq+0xa0/0x100
>> [<ffffff8008276b58>] generic_swap+0x4/0x28
>> [<ffffff800809e108>] kvm_io_bus_register_dev+0xc8/0x110
>> [<ffffff80080ab054>] vgic_register_redist_iodevs+0xd8/0x20c
>> [<ffffff80080a98f8>] vgic_v3_map_resources+0x98/0xec
>> [<ffffff80080a8cd8>] kvm_vgic_map_resources+0x4c/0x6c
>> [<ffffff80080a06d4>] kvm_arch_vcpu_ioctl_run+0x68/0x424
>> [<ffffff800809bc98>] kvm_vcpu_ioctl+0x1b4/0x6f8
>> [<ffffff80081aca98>] do_vfs_ioctl+0x708/0x760
>> [<ffffff80081acb4c>] SyS_ioctl+0x5c/0x8c
>> [<ffffff8008085630>] el0_svc_naked+0x24/0x28
>
> Cheers
> Vladimir
> _______________________________________________
> kvmarm mailing list
> kvmarm at lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
>
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
2016-04-29 14:22 ` Vladimir Murzin
@ 2016-05-02 8:38 ` Christoffer Dall
0 siblings, 0 replies; 94+ messages in thread
From: Christoffer Dall @ 2016-05-02 8:38 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, Apr 29, 2016 at 03:22:51PM +0100, Vladimir Murzin wrote:
> On 29/04/16 15:04, Vladimir Murzin wrote:
> > Hi Andre,
> >
> > On 28/04/16 17:45, Andre Przywara wrote:
> >> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
> >> +{
> >> + int nr_vcpus = atomic_read(&kvm->online_vcpus);
> >> + struct kvm_vcpu *vcpu;
> >> + struct vgic_io_device *devices, *device;
> >> + int c, ret = 0;
> >> +
> >> + devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
> >> + GFP_KERNEL);
> >> + if (!devices)
> >> + return -ENOMEM;
> >> +
> >> + device = devices;
> >> + kvm_for_each_vcpu(c, vcpu, kvm) {
> >> + kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> >> + device->base_addr = redist_base_address;
> >> + device->regions = vgic_v3_redist_registers;
> >> + device->nr_regions = ARRAY_SIZE(vgic_v3_redist_registers);
> >> + device->redist_vcpu = vcpu;
> >> +
> >> + mutex_lock(&kvm->slots_lock);
> >> + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> >> + redist_base_address,
> >> + SZ_64K, &device->dev);
> >> + mutex_unlock(&kvm->slots_lock);
> >> +
> >> + if (ret)
> >> + break;
> >> +
> >> + device++;
> >> + kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> >> + device->base_addr = redist_base_address + SZ_64K;
> >> + device->regions = vgic_v3_private_registers;
> >> + device->nr_regions = ARRAY_SIZE(vgic_v3_private_registers);
> >> + device->redist_vcpu = vcpu;
> >> +
> >> + mutex_lock(&kvm->slots_lock);
> >> + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> >> + redist_base_address + SZ_64K,
> >> + SZ_64K, &device->dev);
> >> + mutex_unlock(&kvm->slots_lock);
> >> + if (ret) {
> >> + kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> >> + &devices[c * 2].dev);
> >> + break;
> >> + }
> >> + device++;
> >> + redist_base_address += 2 * SZ_64K;
> >> + }
> >
> > Can we put cond_resched() somewhere in kvm_for_each_vcpu to avoid
>
> Apologies, it seems to come from kvm_io_bus infrastructure.
>
The stack trace seems to indicate that this comes from the fact that the
kvm_io_bus logic does a full heapsort on the regions for every
insertion. (My analysis skills fails me here as I have no idea what an
arithmetic series of an n*log(n) bound is.)
But if that's the case, then the io_bus framework must either implement
a more clever insertion logic using a better data structure which
optimizes for this case, or provide a way to lock the whole thing,
insert unsorted, and sort in the end.
-Christoffer
>
> > complains with CONFIG_PREEMPT_NONE=y and many many cpus been used?
> >
> >> # lkvm run -k gic-test.flat.a64 -m 316 -c 255 --name guest-727
> >> Info: Loaded kernel to 0x80080000 (69624 bytes)
> >> Info: Placing fdt at 0x8fe00000 - 0x8fffffff
> >> # Warning: The maximum recommended amount of VCPUs is 4
> >> Info: virtio-mmio.devices=0x200 at 0x10000:36
> >>
> >> Info: virtio-mmio.devices=0x200 at 0x10200:37
> >>
> >> Info: virtio-mmio.devices=0x200 at 0x10400:38
> >>
> >> Info: virtio-mmio.devices=0x200 at 0x10600:39
> >>
> >> INFO: rcu_sched self-detected stall on CPU
> >> 0-...: (5249 ticks this GP) idle=589/140000000000001/0 softirq=393/393 fqs=5244
> >> (t=5250 jiffies g=-166 c=-167 q=0)
> >> Task dump for CPU 0:
> >> kvm-vcpu-0 R running task 0 735 1 0x00000002
> >> Call trace:
> >> [<ffffff8008088cc4>] dump_backtrace+0x0/0x194
> >> [<ffffff8008088e6c>] show_stack+0x14/0x1c
> >> [<ffffff80080d4dd0>] sched_show_task+0xa4/0xe8
> >> [<ffffff80080d6ddc>] dump_cpu_task+0x40/0x4c
> >> [<ffffff80080fd398>] rcu_dump_cpu_stacks+0xa8/0xdc
> >> [<ffffff8008100214>] rcu_check_callbacks+0x28c/0x7a4
> >> [<ffffff80081034a8>] update_process_times+0x3c/0x68
> >> [<ffffff8008111820>] tick_sched_handle.isra.15+0x50/0x60
> >> [<ffffff8008111874>] tick_sched_timer+0x44/0x7c
> >> [<ffffff8008103bf8>] __hrtimer_run_queues+0xc8/0x150
> >> [<ffffff8008104110>] hrtimer_interrupt+0x9c/0x1b0
> >> [<ffffff80083b8b74>] arch_timer_handler_phys+0x2c/0x38
> >> [<ffffff80080f6d14>] handle_percpu_devid_irq+0x78/0x98
> >> [<ffffff80080f2a2c>] generic_handle_irq+0x24/0x38
> >> [<ffffff80080f2d98>] __handle_domain_irq+0x84/0xa8
> >> [<ffffff80080825e0>] gic_handle_irq+0x74/0x178
> >> Exception stack(0xffffffc0173e3830 to 0xffffffc0173e3950)
> >> 3820: ffffffc0165ac038 ffffffc0165ac080
> >> 3840: 0000000000000018 0000000000000004 0000000000000014 000000000000003f
> >> 3860: ffffffc0165aeea8 ffffffc000010000 ffffffc017ef5af0 ffffffc0173ecd28
> >> 3880: 000000003fef0000 cfdfdfdf00010000 ffffffc0173ecd50 000000003ff00000
> >> 38a0: cfdfdfdf00010000 0000000000000000 ffffff80081acaf0 0000000000000000
> >> 38c0: 0000000000000000 00000000000000f0 ffffffc0165ac008 0000000000000018
> >> 38e0: ffffff80080992e8 0000000000000078 ffffff8008276b54 0000000000002970
> >> 3900: 0000000000000018 ffffffc0165ac080 ffffffc0165ac038 ffffffc0173e3950
> >> 3920: ffffff8008276d8c ffffffc0173e3950 ffffff8008276b58 0000000020000145
> >> 3940: 0000000000000000 0000000000000001
> >> [<ffffff8008084f20>] el1_irq+0xa0/0x100
> >> [<ffffff8008276b58>] generic_swap+0x4/0x28
> >> [<ffffff800809e108>] kvm_io_bus_register_dev+0xc8/0x110
> >> [<ffffff80080ab054>] vgic_register_redist_iodevs+0xd8/0x20c
> >> [<ffffff80080a98f8>] vgic_v3_map_resources+0x98/0xec
> >> [<ffffff80080a8cd8>] kvm_vgic_map_resources+0x4c/0x6c
> >> [<ffffff80080a06d4>] kvm_arch_vcpu_ioctl_run+0x68/0x424
> >> [<ffffff800809bc98>] kvm_vcpu_ioctl+0x1b4/0x6f8
> >> [<ffffff80081aca98>] do_vfs_ioctl+0x708/0x760
> >> [<ffffff80081acb4c>] SyS_ioctl+0x5c/0x8c
> >> [<ffffff8008085630>] el0_svc_naked+0x24/0x28
> >
> > Cheers
> > Vladimir
> > _______________________________________________
> > kvmarm mailing list
> > kvmarm at lists.cs.columbia.edu
> > https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
> >
> >
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 17/54] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
2016-04-28 16:45 ` [PATCH v2 17/54] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend Andre Przywara
@ 2016-05-02 12:16 ` Marc Zyngier
2016-05-03 8:26 ` Andre Przywara
0 siblings, 1 reply; 94+ messages in thread
From: Marc Zyngier @ 2016-05-02 12:16 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, 28 Apr 2016 17:45:36 +0100
Andre Przywara <andre.przywara@arm.com> wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
>
> Processing maintenance interrupts and accessing the list registers
> are dependent on the host's GIC version.
> Introduce vgic-v2.c to contain GICv2 specific functions.
> Implement the GICv2 specific code for syncing the emulation state
> into the VGIC registers.
>
> 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>
> ---
> Changelog RFC..v1:
> - remove explicit LR_STATE clearing on maintenance interrupt handling
> - improve documentation for vgic_v2_populate_lr()
> - remove WARN_ON on non-edge IRQs in maintenance interrupts
> - simplify multi-CPU source SGI handling
>
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
>
> include/linux/irqchip/arm-gic.h | 1 +
> virt/kvm/arm/vgic/vgic-v2.c | 178 ++++++++++++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic.c | 19 ++---
> virt/kvm/arm/vgic/vgic.h | 6 ++
> 4 files changed, 194 insertions(+), 10 deletions(-)
> create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>
[...]
> @@ -441,14 +447,12 @@ static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> {
> struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> - struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> - u32 model = dist->vgic_model;
> struct vgic_irq *irq;
> int count = 0;
>
> DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(vgic_cpu->ap_list_lock));
>
> - if (unlikely(!dist->enabled))
> + if (unlikely(!vcpu->kvm->arch.vgic.enabled))
> goto out_clean;
>
> if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> @@ -466,14 +470,9 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> * If we get an SGI with multiple sources, try to get
> * them in all at once.
> */
> - if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
> - vgic_irq_is_sgi(irq->intid)) {
> - while (irq->source &&
> - count < kvm_vgic_global_state.nr_lr)
> - vgic_populate_lr(vcpu, irq, count++);
> - } else {
> + do {
> vgic_populate_lr(vcpu, irq, count++);
> - }
> + } while (irq->source && count < kvm_vgic_global_state.nr_lr);
>
> next:
Most, if not all of the changes in this function should be folded in the
previous patch, as we only have generic code in this file (this looks
like a leftover from an earlier rework).
Thanks,
M.
--
Jazz is not dead. It just smells funny.
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 19/54] KVM: arm/arm64: vgic-new: Implement
2016-04-28 16:45 ` [PATCH v2 19/54] KVM: arm/arm64: vgic-new: Implement Andre Przywara
@ 2016-05-02 12:24 ` Eric Auger
2016-05-03 8:26 ` Andre Przywara
0 siblings, 1 reply; 94+ messages in thread
From: Eric Auger @ 2016-05-02 12:24 UTC (permalink / raw)
To: linux-arm-kernel
Hi Andre,
minor comment: patch title has been altered since v1, should be
KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
Cheers
Eric
On 04/28/2016 06:45 PM, 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>
> ---
> Changelog RFC..v1:
> - return false if distributor is disabled
> - add vgic_kick_vcpus() implementations
>
> include/kvm/vgic/vgic.h | 2 ++
> virt/kvm/arm/vgic/vgic.c | 40 ++++++++++++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic.h | 1 +
> 3 files changed, 43 insertions(+)
>
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 5fae4a9..2615205 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -184,6 +184,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 ae52928..eeb766e 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -519,3 +519,43 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> vgic_flush_lr_state(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;
> +
> + if (!vcpu->kvm->arch.vgic.enabled)
> + return 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;
> +}
> +
> +void vgic_kick_vcpus(struct kvm *kvm)
> +{
> + struct kvm_vcpu *vcpu;
> + int c;
> +
> + /*
> + * We've injected an interrupt, time to find out who deserves
> + * a good kick...
> + */
> + kvm_for_each_vcpu(c, vcpu, kvm) {
> + if (kvm_vgic_vcpu_pending_irq(vcpu))
> + kvm_vcpu_kick(vcpu);
> + }
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 81b1a20..0c92cda 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -21,6 +21,7 @@
> struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> u32 intid);
> bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
> +void vgic_kick_vcpus(struct kvm *kvm);
>
> void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
2016-04-28 16:45 ` [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Andre Przywara
2016-04-29 14:04 ` Vladimir Murzin
@ 2016-05-02 16:13 ` Eric Auger
2016-05-05 17:55 ` Andre Przywara
2016-05-03 15:34 ` Marc Zyngier
2 siblings, 1 reply; 94+ messages in thread
From: Eric Auger @ 2016-05-02 16:13 UTC (permalink / raw)
To: linux-arm-kernel
Hi Andre,
Some minor comments below.
On 04/28/2016 06:45 PM, Andre Przywara wrote:
> Create a new file called vgic-mmio-v3.c and describe the GICv3
> distributor and redistributor registers there.
> 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 provide a function to deal with the registration of the two
> separate redistributor frames per VCPU.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - adapt to new MMIO registration approach:
> register one device for the distributor and two for each VCPU
> - implement special handling for private interrupts
> - remove empty stub functions
> - make IGROUPR return RAO
>
> Changelog v1 .. v2:
> - adapt to new framework, introduce vgic-mmio-v3.c
> - remove userland register access functions (for now)
> - precompute .len when describing a VGIC register
> - add missed pointer incrementation on registering redist regions
> - replace _nyi stub functions with raz/wi versions
>
> virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic-mmio.c | 5 +
> virt/kvm/arm/vgic/vgic-mmio.h | 2 +
> virt/kvm/arm/vgic/vgic.h | 3 +
> 4 files changed, 201 insertions(+)
> create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
>
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> new file mode 100644
> index 0000000..c6765d4
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -0,0 +1,191 @@
> +/*
> + * VGICv3 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/irqchip/arm-gic-v3.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/iodev.h>
> +#include <kvm/vgic/vgic.h>
> +
> +#include <asm/kvm_emulate.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +/*
> + * 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(off, read_ops, write_ops, bpi) \
> + { \
> + .reg_offset = off, \
> + .bits_per_irq = bpi, \
> + .len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
> + .read = vgic_mmio_read_raz, \
> + .write = vgic_mmio_write_wi, \
> + }, { \
> + .reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
> + .bits_per_irq = bpi, \
> + .len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8, \
> + .read = read_ops, \
> + .write = write_ops, \
> + }
> +
> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
> + REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> + vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> + REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
> + vgic_mmio_read_rao, 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),
> + REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
> + vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
> + REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
> + vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
would add a comment to say this corresponds to RD_base frame, to use the
same terminology as the spec. IHI0069B.
> +static const struct vgic_register_region vgic_v3_redist_registers[] = {
> + REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
> + vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> + REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
> + vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> + REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
> + vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> + REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
> + vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> + REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
> + vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> + REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
> + vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
same as above: SGI_base frame. Used terminology was a bit misleading for
me since this is also part of redist, 2d frame.
> +static const struct vgic_register_region vgic_v3_private_registers[] = {
> + REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
> + vgic_mmio_read_rao, 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),
> +};
> +
> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
> +{
> + dev->regions = vgic_v3_dist_registers;
> + dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
> +
> + kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
> +
> + return SZ_64K;
> +}
> +
> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
> +{
> + int nr_vcpus = atomic_read(&kvm->online_vcpus);
> + struct kvm_vcpu *vcpu;
> + struct vgic_io_device *devices, *device;
> + int c, ret = 0;
> +
> + devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
> + GFP_KERNEL);
> + if (!devices)
> + return -ENOMEM;
> +
> + device = devices;
> + kvm_for_each_vcpu(c, vcpu, kvm) {
> + kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> + device->base_addr = redist_base_address;
> + device->regions = vgic_v3_redist_registers;
> + device->nr_regions = ARRAY_SIZE(vgic_v3_redist_registers);
> + device->redist_vcpu = vcpu;
> +
> + mutex_lock(&kvm->slots_lock);
> + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> + redist_base_address,
> + SZ_64K, &device->dev);
> + mutex_unlock(&kvm->slots_lock);
> +
> + if (ret)
> + break;
> +
> + device++;
> + kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> + device->base_addr = redist_base_address + SZ_64K;
> + device->regions = vgic_v3_private_registers;
> + device->nr_regions = ARRAY_SIZE(vgic_v3_private_registers);
> + device->redist_vcpu = vcpu;
> +
> + mutex_lock(&kvm->slots_lock);
> + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> + redist_base_address + SZ_64K,
> + SZ_64K, &device->dev);
> + mutex_unlock(&kvm->slots_lock);
> + if (ret) {
> + kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> + &devices[c * 2].dev);
> + break;
> + }
> + device++;
> + redist_base_address += 2 * SZ_64K;
> + }
> +
> + if (ret) {
> + for (c--; c >= 0; c--) {
> + kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> + &devices[c * 2].dev);
> + kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> + &devices[c * 2 + 1].dev);
> + }
> + kfree(devices);
> + } else {
> + kvm->arch.vgic.redist_iodevs = devices;
> + }
> +
> + return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index bf4278c..80d977e 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -502,6 +502,11 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
> case VGIC_V2:
> len = vgic_v2_init_dist_iodev(io_device);
> break;
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> + case VGIC_V3:
> + len = vgic_v3_init_dist_iodev(io_device);
> + break;
> +#endif
> default:
> BUG_ON(1);
> }
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> index 884eb71..3585ac6 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -123,4 +123,6 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>
> unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>
> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
> +
> #endif
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 1ab7d97..6fe07df 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -61,6 +61,9 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
> static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> {
> }
> +
> #endif
>
> +void kvm_register_vgic_device(unsigned long type);
I don't think this relates to this patch.
Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>
Cheers
Eric
> +
> #endif
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 06/54] KVM: arm/arm64: arch_timer: Remove irq_phys_map
2016-04-28 16:45 ` [PATCH v2 06/54] KVM: arm/arm64: arch_timer: Remove irq_phys_map Andre Przywara
@ 2016-05-02 16:44 ` Eric Auger
2016-05-04 10:37 ` Andre Przywara
0 siblings, 1 reply; 94+ messages in thread
From: Eric Auger @ 2016-05-02 16:44 UTC (permalink / raw)
To: linux-arm-kernel
On 04/28/2016 06:45 PM, Andre Przywara wrote:
> Now that the interface between the arch timer and the VGIC does not
> require passing the irq_phys_map entry pointer anymore, let's remove
> it from the virtual arch timer and use the virtual IRQ number instead
> directly.
> The remaining pointer returned by kvm_vgic_map_phys_irq() will be
> removed in the following patch.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - remove extra virt_irq member from struct, instead use irq.irq directly
>
> include/kvm/arm_arch_timer.h | 3 ---
> virt/kvm/arm/arch_timer.c | 11 +++++------
> 2 files changed, 5 insertions(+), 9 deletions(-)
>
> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> index b651aed..a47b7de 100644
> --- a/include/kvm/arm_arch_timer.h
> +++ b/include/kvm/arm_arch_timer.h
> @@ -53,9 +53,6 @@ struct arch_timer_cpu {
> /* Timer IRQ */
> struct kvm_irq_level irq;
>
> - /* VGIC mapping */
> - struct irq_phys_map *map;
> -
> /* Active IRQ state caching */
> bool active_cleared_last;
> };
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index b470632..3a74b17 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -175,10 +175,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->virt_irq,
> + timer->irq.irq,
> timer->irq.level);
> WARN_ON(ret);
> }
> @@ -276,7 +276,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
> * exit.
> */
> phys_active = timer->irq.level ||
> - kvm_vgic_map_is_active(vcpu, timer->map->virt_irq);
> + kvm_vgic_map_is_active(vcpu, timer->irq.irq);
>
> /*
> * We want to avoid hitting the (re)distributor as much as
> @@ -378,7 +378,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
> if (WARN_ON(IS_ERR(map)))
> return PTR_ERR(map);
>
> - timer->map = map;
> return 0;
> }
>
> @@ -521,8 +520,8 @@ 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->virt_irq);
> + if (timer->irq.irq)
> + kvm_vgic_unmap_phys_irq(vcpu, timer->irq.irq);
thought you agreed to always unmap. Is it an oversight or did you change
your mind?
Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>
Cheers
Eric
> }
>
> void kvm_timer_enable(struct kvm *kvm)
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 19/54] KVM: arm/arm64: vgic-new: Implement
2016-05-02 12:24 ` Eric Auger
@ 2016-05-03 8:26 ` Andre Przywara
0 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-05-03 8:26 UTC (permalink / raw)
To: linux-arm-kernel
Hi Eric,
On 02/05/16 13:24, Eric Auger wrote:
> Hi Andre,
>
> minor comment: patch title has been altered since v1, should be
>
> KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
Indeed, that was line-broken accidentally when I added the Changelog.
Thanks for pointing out!
Cheers,
Andre.
> On 04/28/2016 06:45 PM, 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>
>> ---
>> Changelog RFC..v1:
>> - return false if distributor is disabled
>> - add vgic_kick_vcpus() implementations
>>
>> include/kvm/vgic/vgic.h | 2 ++
>> virt/kvm/arm/vgic/vgic.c | 40 ++++++++++++++++++++++++++++++++++++++++
>> virt/kvm/arm/vgic/vgic.h | 1 +
>> 3 files changed, 43 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 5fae4a9..2615205 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -184,6 +184,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 ae52928..eeb766e 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -519,3 +519,43 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>> vgic_flush_lr_state(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;
>> +
>> + if (!vcpu->kvm->arch.vgic.enabled)
>> + return 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;
>> +}
>> +
>> +void vgic_kick_vcpus(struct kvm *kvm)
>> +{
>> + struct kvm_vcpu *vcpu;
>> + int c;
>> +
>> + /*
>> + * We've injected an interrupt, time to find out who deserves
>> + * a good kick...
>> + */
>> + kvm_for_each_vcpu(c, vcpu, kvm) {
>> + if (kvm_vgic_vcpu_pending_irq(vcpu))
>> + kvm_vcpu_kick(vcpu);
>> + }
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 81b1a20..0c92cda 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -21,6 +21,7 @@
>> struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> u32 intid);
>> bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>> +void vgic_kick_vcpus(struct kvm *kvm);
>>
>> void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>> void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>>
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 17/54] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
2016-05-02 12:16 ` Marc Zyngier
@ 2016-05-03 8:26 ` Andre Przywara
0 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-05-03 8:26 UTC (permalink / raw)
To: linux-arm-kernel
On 02/05/16 13:16, Marc Zyngier wrote:
> On Thu, 28 Apr 2016 17:45:36 +0100
> Andre Przywara <andre.przywara@arm.com> wrote:
>
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Processing maintenance interrupts and accessing the list registers
>> are dependent on the host's GIC version.
>> Introduce vgic-v2.c to contain GICv2 specific functions.
>> Implement the GICv2 specific code for syncing the emulation state
>> into the VGIC registers.
>>
>> 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>
>> ---
>> Changelog RFC..v1:
>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>> - improve documentation for vgic_v2_populate_lr()
>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>> - simplify multi-CPU source SGI handling
>>
>> Changelog v1 .. v2:
>> - inject the IRQ priority into the list register
>>
>> include/linux/irqchip/arm-gic.h | 1 +
>> virt/kvm/arm/vgic/vgic-v2.c | 178 ++++++++++++++++++++++++++++++++++++++++
>> virt/kvm/arm/vgic/vgic.c | 19 ++---
>> virt/kvm/arm/vgic/vgic.h | 6 ++
>> 4 files changed, 194 insertions(+), 10 deletions(-)
>> create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>
>
> [...]
>
>> @@ -441,14 +447,12 @@ static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>> static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
>> {
>> struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> - struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>> - u32 model = dist->vgic_model;
>> struct vgic_irq *irq;
>> int count = 0;
>>
>> DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(vgic_cpu->ap_list_lock));
>>
>> - if (unlikely(!dist->enabled))
>> + if (unlikely(!vcpu->kvm->arch.vgic.enabled))
>> goto out_clean;
>>
>> if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
>> @@ -466,14 +470,9 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
>> * If we get an SGI with multiple sources, try to get
>> * them in all at once.
>> */
>> - if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
>> - vgic_irq_is_sgi(irq->intid)) {
>> - while (irq->source &&
>> - count < kvm_vgic_global_state.nr_lr)
>> - vgic_populate_lr(vcpu, irq, count++);
>> - } else {
>> + do {
>> vgic_populate_lr(vcpu, irq, count++);
>> - }
>> + } while (irq->source && count < kvm_vgic_global_state.nr_lr);
>>
>> next:
>
> Most, if not all of the changes in this function should be folded in the
> previous patch, as we only have generic code in this file (this looks
> like a leftover from an earlier rework).
Oh dear, you are totally right. Sorry for the mess!
Will fix it!
Cheers,
Andre.
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 42/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
2016-04-28 16:46 ` [PATCH v2 42/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers Andre Przywara
@ 2016-05-03 9:59 ` Marc Zyngier
2016-05-03 10:09 ` Andre Przywara
0 siblings, 1 reply; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 9:59 UTC (permalink / raw)
To: linux-arm-kernel
On 28/04/16 17:46, Andre Przywara wrote:
> 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-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
> virt/kvm/arm/vgic/vgic-mmio-v2.c | 34 ++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic.h | 1 +
> 3 files changed, 86 insertions(+), 2 deletions(-)
>
[...]
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index ae6077e..f2a8efe 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -276,3 +276,37 @@ int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>
> return ret;
> }
> +
> +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;
> + const 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 */
This definitely needs addressing, as it breaks guest migration.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 42/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
2016-05-03 9:59 ` Marc Zyngier
@ 2016-05-03 10:09 ` Andre Przywara
2016-05-03 10:12 ` Marc Zyngier
2016-05-03 10:16 ` Marc Zyngier
0 siblings, 2 replies; 94+ messages in thread
From: Andre Przywara @ 2016-05-03 10:09 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
On 03/05/16 10:59, Marc Zyngier wrote:
> On 28/04/16 17:46, Andre Przywara wrote:
>> 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-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
>> virt/kvm/arm/vgic/vgic-mmio-v2.c | 34 ++++++++++++++++++++++++
>> virt/kvm/arm/vgic/vgic.h | 1 +
>> 3 files changed, 86 insertions(+), 2 deletions(-)
>>
>
> [...]
>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index ae6077e..f2a8efe 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -276,3 +276,37 @@ int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>
>> return ret;
>> }
>> +
>> +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;
>> + const 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 */
>
> This definitely needs addressing, as it breaks guest migration.
It is implemented in patch 46/54.
Shall I remove the TODO to avoid confusion and/or replace it with a note
either in a comment or in this commit message that the implementation
will follow in one the next patches?
Cheers,
Andre.
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 42/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
2016-05-03 10:09 ` Andre Przywara
@ 2016-05-03 10:12 ` Marc Zyngier
2016-05-03 10:16 ` Marc Zyngier
1 sibling, 0 replies; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 10:12 UTC (permalink / raw)
To: linux-arm-kernel
On 03/05/16 11:09, Andre Przywara wrote:
> Hi,
>
> On 03/05/16 10:59, Marc Zyngier wrote:
>> On 28/04/16 17:46, Andre Przywara wrote:
>>> 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-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
>>> virt/kvm/arm/vgic/vgic-mmio-v2.c | 34 ++++++++++++++++++++++++
>>> virt/kvm/arm/vgic/vgic.h | 1 +
>>> 3 files changed, 86 insertions(+), 2 deletions(-)
>>>
>>
>> [...]
>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> index ae6077e..f2a8efe 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> @@ -276,3 +276,37 @@ int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>>
>>> return ret;
>>> }
>>> +
>>> +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;
>>> + const 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 */
>>
>> This definitely needs addressing, as it breaks guest migration.
>
> It is implemented in patch 46/54.
Ah, sorry. I was on my way there...
> Shall I remove the TODO to avoid confusion and/or replace it with a note
> either in a comment or in this commit message that the implementation
> will follow in one the next patches?
Just drop the comment.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 42/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
2016-05-03 10:09 ` Andre Przywara
2016-05-03 10:12 ` Marc Zyngier
@ 2016-05-03 10:16 ` Marc Zyngier
2016-05-03 16:07 ` [PATCH] KVM: arm/arm64: new-vgic: add proper GICv2 CPU interface userland access Andre Przywara
1 sibling, 1 reply; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 10:16 UTC (permalink / raw)
To: linux-arm-kernel
On 03/05/16 11:09, Andre Przywara wrote:
> Hi,
>
> On 03/05/16 10:59, Marc Zyngier wrote:
>> On 28/04/16 17:46, Andre Przywara wrote:
>>> 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-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
>>> virt/kvm/arm/vgic/vgic-mmio-v2.c | 34 ++++++++++++++++++++++++
>>> virt/kvm/arm/vgic/vgic.h | 1 +
>>> 3 files changed, 86 insertions(+), 2 deletions(-)
>>>
>>
>> [...]
>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> index ae6077e..f2a8efe 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> @@ -276,3 +276,37 @@ int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>>
>>> return ret;
>>> }
>>> +
>>> +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;
>>> + const 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 */
>>
>> This definitely needs addressing, as it breaks guest migration.
>
> It is implemented in patch 46/54.
> Shall I remove the TODO to avoid confusion and/or replace it with a note
> either in a comment or in this commit message that the implementation
> will follow in one the next patches?
I just checked, and I stand by my initial comment. Patch 46 does
implement the accessors, but nothing actually wires them here.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 46/54] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
2016-04-28 16:46 ` [PATCH v2 46/54] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access Andre Przywara
@ 2016-05-03 10:21 ` Marc Zyngier
0 siblings, 0 replies; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 10:21 UTC (permalink / raw)
To: linux-arm-kernel
On 28/04/16 17:46, Andre Przywara wrote:
> Using the VMCR accessors we provide access to GIC CPU interface state
> to userland by wiring it up to the existing userland interface.
>
> 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 38260ae..eaf5c1d 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_uaccess(vcpu, is_write, addr, reg);
>
Shouldn't we have this implemented as an MMIO table, and moved to the
vgic-v2-mmio.c file?
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 50/54] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
2016-04-28 16:46 ` [PATCH v2 50/54] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources Andre Przywara
@ 2016-05-03 10:47 ` Marc Zyngier
0 siblings, 0 replies; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 10:47 UTC (permalink / raw)
To: linux-arm-kernel
On 28/04/16 17:46, Andre Przywara wrote:
> 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-init.c | 27 +++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic-v2.c | 47 +++++++++++++++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic-v3.c | 44 ++++++++++++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic.h | 16 +++++++++++++++
> 5 files changed, 135 insertions(+)
[...]
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 444210f..f970e3e 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -43,6 +43,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_iodev(struct kvm *kvm, gpa_t dist_base_address,
> + enum vgic_type);
>
> #ifdef CONFIG_KVM_ARM_VGIC_V3
> void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> @@ -54,6 +57,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_iodevs(struct kvm *kvm, gpa_t dist_base_address);
> #else
> static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> {
> @@ -94,6 +99,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_iodevs(struct kvm *kvm,
> + gpa_t dist_base_address)
> +{
> + return -ENODEV;
> +}
It would make sense to move this stub to patch 32, where the non-stub
implementation is.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 05/54] KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map
2016-04-28 16:45 ` [PATCH v2 05/54] KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map Andre Przywara
@ 2016-05-03 12:15 ` Marc Zyngier
0 siblings, 0 replies; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 12:15 UTC (permalink / raw)
To: linux-arm-kernel
On 28/04/16 17:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
>
> The communication of a Linux IRQ number from outside the VGIC to the
> vgic was a leftover from the day when the vgic code cared about how a
> particular device injects virtual interrupts mapped to a physical
> interrupt.
>
> We can safely remove this notion, leaving all physical IRQ handling to
> be done in the device driver (the arch timer in this case), which makes
> room for a saner API for the new VGIC.
>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> ---
> Changelog v1 .. v2:
> - update kerneldoc comments on kvm_vgic_map_phys_irq()
>
> include/kvm/arm_vgic.h | 3 +--
> virt/kvm/arm/arch_timer.c | 22 ++++++++++++++++++++--
> virt/kvm/arm/vgic.c | 28 ++++++----------------------
> 3 files changed, 27 insertions(+), 26 deletions(-)
>
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 43eeb18..49c559e 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, unsigned int virt_irq);
> bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index 58b2439..b470632 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -301,7 +301,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);
> @@ -334,6 +334,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
> @@ -353,10 +356,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);
Consider adding a #include <linux/irq.h> at the top of this file. Things
do break once the linux/of_irq.h include is removed with the KVM/ACPI
patches.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 47/54] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
2016-04-28 16:46 ` [PATCH v2 47/54] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init Andre Przywara
@ 2016-05-03 15:02 ` Marc Zyngier
2016-05-03 15:35 ` Marc Zyngier
1 sibling, 0 replies; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 15:02 UTC (permalink / raw)
To: linux-arm-kernel
On 28/04/16 17:46, Andre Przywara wrote:
> 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>
> ---
> Changelog v1 .. v2:
> - rename vgic_init.c to vgic-init.c
>
> include/kvm/vgic/vgic.h | 1 +
> virt/kvm/arm/vgic/vgic-init.c | 122 ++++++++++++++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic-v2.c | 90 +++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic-v3.c | 74 +++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic.h | 6 +++
> 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 cfc3640..d144e3d 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -202,6 +202,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-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;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 70cac63..00dc166 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"
>
> @@ -205,3 +210,88 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> vmcrp->pmr = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
> GICH_VMCR_PRIMASK_SHIFT;
> }
> +
> +/**
> + * 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 2c55bd5..a2026c2 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;
> +
This can be dropped...
> void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> {
> struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> @@ -189,3 +197,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;
and defined here (no need for a global variable anymore now that we have
a global state).
> +
> + 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 ea72f32..d6fe7b4 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -41,6 +41,7 @@ int vgic_v2_dist_uaccess(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_process_maintenance(struct kvm_vcpu *vcpu);
> @@ -50,6 +51,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
> void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> 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_process_maintenance(struct kvm_vcpu *vcpu)
> {
> @@ -82,6 +84,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);
>
Depending on the merge order with Julien's series, it could be worth
squashing my rework into this patch.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 21/54] KVM: arm/arm64: vgic-new: Add GICv2 MMIO handling framework
2016-04-28 16:45 ` [PATCH v2 21/54] KVM: arm/arm64: vgic-new: Add GICv2 " Andre Przywara
@ 2016-05-03 15:32 ` Marc Zyngier
0 siblings, 0 replies; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 15:32 UTC (permalink / raw)
To: linux-arm-kernel
On 28/04/16 17:45, Andre Przywara wrote:
> Create vgic-mmio-v2.c to describe GICv2 emulation specific handlers
> using the initializer macros provided by the VGIC MMIO framework.
> Provide a function to register the GICv2 distributor registers to
> the kvm_io_bus framework.
> The actual handler functions are still stubs in this patch.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> Changelog v1 .. v2:
> - new patch, split out from the generic MMIO framework patch
> - use a separate file to hold GICv2 emulation specific handlers
> - replace _nyi stub functions with raz/wi versions
>
> virt/kvm/arm/vgic/vgic-mmio-v2.c | 62 ++++++++++++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic-mmio.c | 26 +++++++++++++++++
> virt/kvm/arm/vgic/vgic-mmio.h | 2 ++
> 3 files changed, 90 insertions(+)
> create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v2.c
>
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> new file mode 100644
> index 0000000..afee778
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -0,0 +1,62 @@
> +/*
> + * VGICv2 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/irqchip/arm-gic.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/iodev.h>
> +#include <kvm/vgic/vgic.h>
Please use kvm/arm_vgic.h so that it doesn't break once we rename
kvm/vgic/vgic.h.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
2016-04-28 16:45 ` [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Andre Przywara
2016-04-29 14:04 ` Vladimir Murzin
2016-05-02 16:13 ` Eric Auger
@ 2016-05-03 15:34 ` Marc Zyngier
2 siblings, 0 replies; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 15:34 UTC (permalink / raw)
To: linux-arm-kernel
On 28/04/16 17:45, Andre Przywara wrote:
> Create a new file called vgic-mmio-v3.c and describe the GICv3
> distributor and redistributor registers there.
> 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 provide a function to deal with the registration of the two
> separate redistributor frames per VCPU.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - adapt to new MMIO registration approach:
> register one device for the distributor and two for each VCPU
> - implement special handling for private interrupts
> - remove empty stub functions
> - make IGROUPR return RAO
>
> Changelog v1 .. v2:
> - adapt to new framework, introduce vgic-mmio-v3.c
> - remove userland register access functions (for now)
> - precompute .len when describing a VGIC register
> - add missed pointer incrementation on registering redist regions
> - replace _nyi stub functions with raz/wi versions
>
> virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic-mmio.c | 5 +
> virt/kvm/arm/vgic/vgic-mmio.h | 2 +
> virt/kvm/arm/vgic/vgic.h | 3 +
> 4 files changed, 201 insertions(+)
> create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
>
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> new file mode 100644
> index 0000000..c6765d4
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -0,0 +1,191 @@
> +/*
> + * VGICv3 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/irqchip/arm-gic-v3.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/iodev.h>
> +#include <kvm/vgic/vgic.h>
Same remark about the use of this include file instead of kvm/arm_vgic.h.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 47/54] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
2016-04-28 16:46 ` [PATCH v2 47/54] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init Andre Przywara
2016-05-03 15:02 ` Marc Zyngier
@ 2016-05-03 15:35 ` Marc Zyngier
1 sibling, 0 replies; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 15:35 UTC (permalink / raw)
To: linux-arm-kernel
On 28/04/16 17:46, Andre Przywara wrote:
> 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>
> ---
> Changelog v1 .. v2:
> - rename vgic_init.c to vgic-init.c
>
> include/kvm/vgic/vgic.h | 1 +
> virt/kvm/arm/vgic/vgic-init.c | 122 ++++++++++++++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic-v2.c | 90 +++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic-v3.c | 74 +++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic.h | 6 +++
> 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 cfc3640..d144e3d 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -202,6 +202,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-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>
Same issue here as well.
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH] KVM: arm/arm64: new-vgic: add proper GICv2 CPU interface userland access
2016-05-03 10:16 ` Marc Zyngier
@ 2016-05-03 16:07 ` Andre Przywara
2016-05-03 17:00 ` Marc Zyngier
0 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-05-03 16:07 UTC (permalink / raw)
To: linux-arm-kernel
Although the actual register access was wired, the availability check
for the GICv2 CPU interface register interface was not - leading to
any attempt of saving or restoring GICv2 CPU i/f registers to fail.
This patch fixes this by modelling the CPU i/f registers similarily to
the distributor registers, thereby piggy backing on the existing
distributor save/restore code to do the heavy lifting.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Hi,
this is a fix for the missing CPU i/f migration that Marc spotted.
In a repost I will merge this somehow into the existing patches, but
for now this goes on top of the series.
Can any of you have a look whether this is the right way to go?
Cheers,
Andre.
virt/kvm/arm/vgic/vgic-kvm-device.c | 71 +--------------------
virt/kvm/arm/vgic/vgic-mmio-v2.c | 122 +++++++++++++++++++++++++++++++++---
virt/kvm/arm/vgic/vgic.h | 2 +
3 files changed, 115 insertions(+), 80 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index eaf5c1d..657552d 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -20,8 +20,6 @@
#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)
@@ -255,69 +253,6 @@ 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
@@ -366,11 +301,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
switch (attr->group) {
case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
- ret = 0;
- if (is_write)
- vgic_write_vcpuif(vcpu, addr, *reg);
- else
- *reg = vgic_read_vcpuif(vcpu, addr);
+ ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
break;
case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index f2a8efe..276c3a0 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -206,6 +206,74 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
}
}
+#define GICC_ARCH_VERSION_V2 0x2
+
+/* These are for userland accesses only, there is no guest-facing emulation. */
+static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ struct vgic_vmcr vmcr;
+ u32 *field;
+
+ switch (addr & 0xff) {
+ 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 extract_bytes((PRODUCT_ID_KVM << 20) |
+ (GICC_ARCH_VERSION_V2 << 16) |
+ (IMPLEMENTER_ARM << 0),
+ addr & 3, len);
+ default:
+ return 0;
+ }
+
+ vgic_get_vmcr(vcpu, &vmcr);
+
+ return extract_bytes(*field, addr & 3, len);
+}
+
+static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ struct vgic_vmcr vmcr;
+ u32 *field;
+
+ switch (addr & 0xff) {
+ 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;
+ }
+
+ vgic_get_vmcr(vcpu, &vmcr);
+ if (*field == val)
+ return;
+
+ *field = val;
+ vgic_set_vmcr(vcpu, &vmcr);
+}
+
static const 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),
@@ -237,6 +305,21 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
};
+static const struct vgic_register_region vgic_v2_cpu_registers[] = {
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_CTRL,
+ vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_PRIMASK,
+ vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_BINPOINT,
+ vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_ALIAS_BINPOINT,
+ vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_ACTIVEPRIO,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT,
+ vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+};
+
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
{
dev->regions = vgic_v2_dist_registers;
@@ -253,23 +336,18 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
* have to set up a buffer similar to what would have happened if a guest MMIO
* access occurred, including doing endian conversions on BE systems.
*/
-int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
- int offset, u32 *val)
+static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
+ bool is_write, int offset, u32 *val)
{
unsigned int len = 4;
u8 buf[4];
int ret;
- struct vgic_io_device dev = {
- .regions = vgic_v2_dist_registers,
- .nr_regions = ARRAY_SIZE(vgic_v2_dist_registers),
- };
-
if (is_write) {
vgic_data_host_to_mmio_bus(buf, len, *val);
- ret = kvm_io_gic_ops.write(vcpu, &dev.dev, offset, len, buf);
+ ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
} else {
- ret = kvm_io_gic_ops.read(vcpu, &dev.dev, offset, len, buf);
+ ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
if (!ret)
*val = vgic_data_mmio_bus_to_host(buf, len);
}
@@ -277,6 +355,28 @@ int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
return ret;
}
+int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *val)
+{
+ struct vgic_io_device dev = {
+ .regions = vgic_v2_cpu_registers,
+ .nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
+ };
+
+ return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
+
+int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *val)
+{
+ struct vgic_io_device dev = {
+ .regions = vgic_v2_dist_registers,
+ .nr_regions = ARRAY_SIZE(vgic_v2_dist_registers),
+ };
+
+ return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
+
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;
@@ -292,7 +392,9 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
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 */
+ regions = vgic_v2_cpu_registers;
+ nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers);
+ break;
default:
return -ENXIO;
}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index f970e3e..d1de87f 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -38,6 +38,8 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
int offset, u32 *val);
+int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *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);
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
2016-04-28 16:45 ` [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 " Andre Przywara
@ 2016-05-03 16:16 ` Marc Zyngier
2016-05-04 13:30 ` Andre Przywara
2016-05-05 17:04 ` [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend Tom Hanson
1 sibling, 1 reply; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 16:16 UTC (permalink / raw)
To: linux-arm-kernel
On 28/04/16 17:45, 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.
> 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>
> ---
> Changelog RFC..v1:
> - remove outdated comment about the dist_lock
> - add WARN_ON about LR_STATE not being 0 in maintenance interrupts
>
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
>
> include/linux/irqchip/arm-gic-v3.h | 1 +
> virt/kvm/arm/vgic/vgic-v3.c | 169 +++++++++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic.c | 25 ++++--
> virt/kvm/arm/vgic/vgic.h | 29 +++++++
> 4 files changed, 219 insertions(+), 5 deletions(-)
> create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index d5d798b..56fd2c5 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -275,6 +275,7 @@
> #define ICH_LR_ACTIVE_BIT (1ULL << 63)
> #define ICH_LR_PHYS_ID_SHIFT 32
> #define ICH_LR_PHYS_ID_MASK (0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
> +#define ICH_LR_PRIORITY_SHIFT 48
>
> #define ICH_MISR_EOI (1 << 0)
> #define ICH_MISR_U (1 << 1)
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> new file mode 100644
> index 0000000..461229b
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -0,0 +1,169 @@
> +/*
> + * 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>
This last line is definitely a (copy-paste) bug. We should never include
both GIC headers in the same file. Can you please drop that line and
have the following hunk instead?
+/* These are for GICv2 emulation only */
+#define GICH_LR_VIRTUALID (0x3ffUL << 0)
+#define GICH_LR_PHYSID_CPUID_SHIFT (10)
+#define GICH_LR_PHYSID_CPUID (7UL << GICH_LR_PHYSID_CPUID_SHIFT)
+#define ICH_LR_VIRTUALID_MASK (BIT_ULL(32) - 1)
+
which is similar to what we have in the old implementation, for the
exact same reason.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH] KVM: arm/arm64: new-vgic: add proper GICv2 CPU interface userland access
2016-05-03 16:07 ` [PATCH] KVM: arm/arm64: new-vgic: add proper GICv2 CPU interface userland access Andre Przywara
@ 2016-05-03 17:00 ` Marc Zyngier
2016-05-03 17:59 ` Marc Zyngier
0 siblings, 1 reply; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 17:00 UTC (permalink / raw)
To: linux-arm-kernel
On 03/05/16 17:07, Andre Przywara wrote:
> Although the actual register access was wired, the availability check
> for the GICv2 CPU interface register interface was not - leading to
> any attempt of saving or restoring GICv2 CPU i/f registers to fail.
>
> This patch fixes this by modelling the CPU i/f registers similarily to
> the distributor registers, thereby piggy backing on the existing
> distributor save/restore code to do the heavy lifting.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Hi,
>
> this is a fix for the missing CPU i/f migration that Marc spotted.
> In a repost I will merge this somehow into the existing patches, but
> for now this goes on top of the series.
> Can any of you have a look whether this is the right way to go?
The whole VMCR story feels very convoluted. It caters for GICv3 (which
has no way to use it), has global symbols where it should be static,
and indirections that serve no apparent purpose. And the vgic_vmcr
structure should really per implementation. </rant> ;-)
So here's my take on this particular patch:
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 64aca0c..2a6fa99 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -172,13 +172,6 @@ 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-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index eaf5c1d..657552d 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -20,8 +20,6 @@
#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)
@@ -255,69 +253,6 @@ 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
@@ -366,11 +301,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
switch (attr->group) {
case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
- ret = 0;
- if (is_write)
- vgic_write_vcpuif(vcpu, addr, *reg);
- else
- *reg = vgic_read_vcpuif(vcpu, addr);
+ ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
break;
case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index f2a8efe..9598426 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -206,6 +206,104 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
}
}
+struct vgic_vmcr {
+ u32 ctlr;
+ u32 abpr;
+ u32 bpr;
+ u32 pmr;
+};
+
+static 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;
+}
+
+static 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;
+}
+
+#define GICC_ARCH_VERSION_V2 0x2
+
+/* These are for userland accesses only, there is no guest-facing emulation. */
+static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ struct vgic_vmcr vmcr;
+ u32 val;
+
+ vgic_v2_get_vmcr(vcpu, &vmcr);
+
+ switch (addr & 0xff) {
+ case GIC_CPU_CTRL:
+ val = vmcr.ctlr;
+ break;
+ case GIC_CPU_PRIMASK:
+ val = vmcr.pmr;
+ break;
+ case GIC_CPU_BINPOINT:
+ val = vmcr.bpr;
+ break;
+ case GIC_CPU_ALIAS_BINPOINT:
+ val = vmcr.abpr;
+ break;
+ case GIC_CPU_IDENT:
+ val = ((PRODUCT_ID_KVM << 20) |
+ (GICC_ARCH_VERSION_V2 << 16) |
+ IMPLEMENTER_ARM);
+ break;
+ default:
+ return 0;
+ }
+
+ return extract_bytes(val, addr & 3, len);
+}
+
+static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ struct vgic_vmcr vmcr;
+
+ vgic_v2_get_vmcr(vcpu, &vmcr);
+
+ switch (addr & 0xff) {
+ case GIC_CPU_CTRL:
+ vmcr.ctlr = val;
+ break;
+ case GIC_CPU_PRIMASK:
+ vmcr.pmr = val;
+ break;
+ case GIC_CPU_BINPOINT:
+ vmcr.bpr = val;
+ break;
+ case GIC_CPU_ALIAS_BINPOINT:
+ vmcr.abpr = val;
+ break;
+ }
+
+ vgic_v2_set_vmcr(vcpu, &vmcr);
+}
+
static const 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),
@@ -237,6 +335,21 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
};
+static const struct vgic_register_region vgic_v2_cpu_registers[] = {
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_CTRL,
+ vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_PRIMASK,
+ vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_BINPOINT,
+ vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_ALIAS_BINPOINT,
+ vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_ACTIVEPRIO,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+ REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT,
+ vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+};
+
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
{
dev->regions = vgic_v2_dist_registers;
@@ -253,23 +366,18 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
* have to set up a buffer similar to what would have happened if a guest MMIO
* access occurred, including doing endian conversions on BE systems.
*/
-int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
- int offset, u32 *val)
+static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
+ bool is_write, int offset, u32 *val)
{
unsigned int len = 4;
u8 buf[4];
int ret;
- struct vgic_io_device dev = {
- .regions = vgic_v2_dist_registers,
- .nr_regions = ARRAY_SIZE(vgic_v2_dist_registers),
- };
-
if (is_write) {
vgic_data_host_to_mmio_bus(buf, len, *val);
- ret = kvm_io_gic_ops.write(vcpu, &dev.dev, offset, len, buf);
+ ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
} else {
- ret = kvm_io_gic_ops.read(vcpu, &dev.dev, offset, len, buf);
+ ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
if (!ret)
*val = vgic_data_mmio_bus_to_host(buf, len);
}
@@ -277,6 +385,28 @@ int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
return ret;
}
+int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *val)
+{
+ struct vgic_io_device dev = {
+ .regions = vgic_v2_cpu_registers,
+ .nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
+ };
+
+ return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
+
+int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *val)
+{
+ struct vgic_io_device dev = {
+ .regions = vgic_v2_dist_registers,
+ .nr_regions = ARRAY_SIZE(vgic_v2_dist_registers),
+ };
+
+ return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
+
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;
@@ -292,7 +422,9 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
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 */
+ regions = vgic_v2_cpu_registers;
+ nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers);
+ break;
default:
return -ENXIO;
}
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index b8bfece..862fb0f 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -182,35 +182,6 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
}
-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_enable(struct kvm_vcpu *vcpu)
{
/*
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index e975a33..ed85bbc 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -176,28 +176,6 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
}
-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;
-}
-
void vgic_v3_enable(struct kvm_vcpu *vcpu)
{
struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 5f21742..b22e2ac 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -482,22 +482,6 @@ 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 f970e3e..9072b8c 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -38,9 +38,9 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
int offset, u32 *val);
+int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *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);
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);
@@ -53,8 +53,6 @@ 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_clear_lr(struct kvm_vcpu *vcpu, int lr);
void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
-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);
@@ -81,16 +79,6 @@ static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
{
}
-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)
-{
-}
-
static inline void vgic_v3_enable(struct kvm_vcpu *vcpu)
{
}
@@ -112,9 +100,6 @@ static inline int vgic_register_redist_iodevs(struct kvm *kvm,
}
#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);
-
int vgic_lazy_init(struct kvm *kvm);
int vgic_init(struct kvm *kvm);
void kvm_register_vgic_device(unsigned long type);
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH] KVM: arm/arm64: new-vgic: add proper GICv2 CPU interface userland access
2016-05-03 17:00 ` Marc Zyngier
@ 2016-05-03 17:59 ` Marc Zyngier
0 siblings, 0 replies; 94+ messages in thread
From: Marc Zyngier @ 2016-05-03 17:59 UTC (permalink / raw)
To: linux-arm-kernel
On 03/05/16 18:00, Marc Zyngier wrote:
> On 03/05/16 17:07, Andre Przywara wrote:
>> Although the actual register access was wired, the availability check
>> for the GICv2 CPU interface register interface was not - leading to
>> any attempt of saving or restoring GICv2 CPU i/f registers to fail.
>>
>> This patch fixes this by modelling the CPU i/f registers similarily to
>> the distributor registers, thereby piggy backing on the existing
>> distributor save/restore code to do the heavy lifting.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Hi,
>>
>> this is a fix for the missing CPU i/f migration that Marc spotted.
>> In a repost I will merge this somehow into the existing patches, but
>> for now this goes on top of the series.
>> Can any of you have a look whether this is the right way to go?
>
> The whole VMCR story feels very convoluted. It caters for GICv3 (which
> has no way to use it), has global symbols where it should be static,
> and indirections that serve no apparent purpose. And the vgic_vmcr
> structure should really per implementation. </rant> ;-)
>
> So here's my take on this particular patch:
[... lots of stupid code deleted ...]
Which is completely wrong. I missed the case where we emulate GICv2 on GICv3. So, here's a much smaller patch that goes on top of yours (making the vmcr accessors static and reworking the MMIO handlers):
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index dddd8e1..1967a52 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -206,6 +206,22 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
}
}
+static 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);
+}
+
+static 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);
+}
+
#define GICC_ARCH_VERSION_V2 0x2
/* These are for userland accesses only, there is no guest-facing emulation. */
@@ -213,33 +229,33 @@ static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len)
{
struct vgic_vmcr vmcr;
- u32 *field;
+ u32 val;
+
+ vgic_get_vmcr(vcpu, &vmcr);
switch (addr & 0xff) {
case GIC_CPU_CTRL:
- field = &vmcr.ctlr;
+ val = vmcr.ctlr;
break;
case GIC_CPU_PRIMASK:
- field = &vmcr.pmr;
+ val = vmcr.pmr;
break;
case GIC_CPU_BINPOINT:
- field = &vmcr.bpr;
+ val = vmcr.bpr;
break;
case GIC_CPU_ALIAS_BINPOINT:
- field = &vmcr.abpr;
+ val = vmcr.abpr;
break;
case GIC_CPU_IDENT:
- return extract_bytes((PRODUCT_ID_KVM << 20) |
- (GICC_ARCH_VERSION_V2 << 16) |
- (IMPLEMENTER_ARM << 0),
- addr & 3, len);
+ val = ((PRODUCT_ID_KVM << 20) |
+ (GICC_ARCH_VERSION_V2 << 16) |
+ IMPLEMENTER_ARM);
+ break;
default:
return 0;
}
- vgic_get_vmcr(vcpu, &vmcr);
-
- return extract_bytes(*field, addr & 3, len);
+ return extract_bytes(val, addr & 3, len);
}
static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
@@ -247,30 +263,24 @@ static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
unsigned long val)
{
struct vgic_vmcr vmcr;
- u32 *field;
+
+ vgic_get_vmcr(vcpu, &vmcr);
switch (addr & 0xff) {
case GIC_CPU_CTRL:
- field = &vmcr.ctlr;
+ vmcr.ctlr = val;
break;
case GIC_CPU_PRIMASK:
- field = &vmcr.pmr;
+ vmcr.pmr = val;
break;
case GIC_CPU_BINPOINT:
- field = &vmcr.bpr;
+ vmcr.bpr = val;
break;
case GIC_CPU_ALIAS_BINPOINT:
- field = &vmcr.abpr;
+ vmcr.abpr = val;
break;
- default:
- return;
}
- vgic_get_vmcr(vcpu, &vmcr);
- if (*field == val)
- return;
-
- *field = val;
vgic_set_vmcr(vcpu, &vmcr);
}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 5f21742..b22e2ac 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -482,22 +482,6 @@ 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 c1f3751..800be90 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -116,9 +116,6 @@ static inline int vgic_register_redist_iodevs(struct kvm *kvm,
}
#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);
-
int vgic_lazy_init(struct kvm *kvm);
int vgic_init(struct kvm *kvm);
void kvm_register_vgic_device(unsigned long type);
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH v2 07/54] KVM: arm/arm64: vgic: Remove irq_phys_map from interface
2016-04-28 16:45 ` [PATCH v2 07/54] KVM: arm/arm64: vgic: Remove irq_phys_map from interface Andre Przywara
@ 2016-05-03 22:22 ` Tom Hanson
0 siblings, 0 replies; 94+ messages in thread
From: Tom Hanson @ 2016-05-03 22:22 UTC (permalink / raw)
To: linux-arm-kernel
On 04/28/2016 10:45 AM, Andre Przywara wrote:
...
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index 3a74b17..9475000 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -333,10 +333,10 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
...
> + ret = kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
> + if (ret)
> + return ret;
>
> return 0;
> }
This isn't wrong, but it is overly complicated. I'd recommend either:
ret = kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
return ret;
OR
return kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 14/54] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
2016-04-28 16:45 ` [PATCH v2 14/54] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection Andre Przywara
@ 2016-05-03 23:46 ` Tom Hanson
2016-05-05 11:24 ` Andre Przywara
0 siblings, 1 reply; 94+ messages in thread
From: Tom Hanson @ 2016-05-03 23:46 UTC (permalink / raw)
To: linux-arm-kernel
On 04/28/2016 10:45 AM, Andre Przywara wrote:
...
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index fb45537..92b78a0 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -19,8 +19,31 @@
...
> +/*
> + * 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);
> + */
The code would be safer and easier to maintain in the long run if there were functions provided which implement these 2 rules. Something along the line of:
void vgic_lock_aplist_irq(spinlock_t ap_list_lock, spinlock_t irq_lock){
spin_lock(ap_list_lock);
spin_lock(irq_lock);
}
and (borrowing from patch 16/54):
void vgic_lock_cpu_aplist_pair(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2){
struct kvm_vcpu *vcpuA, *vcpuB;
/*
* Ensure locking order by always locking the smallest
* ID first.
*/
if (vcpu1->vcpu_id < vcpu2->vcpu_id) {
vcpuA = vcpu1;
vcpuB = vcpu2;
} else {
vcpuA = vcpu2;
vcpuB = vcpu1;
}
spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
}
With, of course the matching unlock functions.
Then, as long as new code calls the correct function, the order is always correct. Easy to write, easy to review. And beats the heck out of chasing a deadlock at some point in the future.
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 06/54] KVM: arm/arm64: arch_timer: Remove irq_phys_map
2016-05-02 16:44 ` Eric Auger
@ 2016-05-04 10:37 ` Andre Przywara
0 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-05-04 10:37 UTC (permalink / raw)
To: linux-arm-kernel
Hi Eric,
On 02/05/16 17:44, Eric Auger wrote:
> On 04/28/2016 06:45 PM, Andre Przywara wrote:
>> Now that the interface between the arch timer and the VGIC does not
>> require passing the irq_phys_map entry pointer anymore, let's remove
>> it from the virtual arch timer and use the virtual IRQ number instead
>> directly.
>> The remaining pointer returned by kvm_vgic_map_phys_irq() will be
>> removed in the following patch.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog v1 .. v2:
>> - remove extra virt_irq member from struct, instead use irq.irq directly
>>
>> include/kvm/arm_arch_timer.h | 3 ---
>> virt/kvm/arm/arch_timer.c | 11 +++++------
>> 2 files changed, 5 insertions(+), 9 deletions(-)
>>
>> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
>> index b651aed..a47b7de 100644
>> --- a/include/kvm/arm_arch_timer.h
>> +++ b/include/kvm/arm_arch_timer.h
>> @@ -53,9 +53,6 @@ struct arch_timer_cpu {
>> /* Timer IRQ */
>> struct kvm_irq_level irq;
>>
>> - /* VGIC mapping */
>> - struct irq_phys_map *map;
>> -
>> /* Active IRQ state caching */
>> bool active_cleared_last;
>> };
>> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
>> index b470632..3a74b17 100644
>> --- a/virt/kvm/arm/arch_timer.c
>> +++ b/virt/kvm/arm/arch_timer.c
>> @@ -175,10 +175,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->virt_irq,
>> + timer->irq.irq,
>> timer->irq.level);
>> WARN_ON(ret);
>> }
>> @@ -276,7 +276,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
>> * exit.
>> */
>> phys_active = timer->irq.level ||
>> - kvm_vgic_map_is_active(vcpu, timer->map->virt_irq);
>> + kvm_vgic_map_is_active(vcpu, timer->irq.irq);
>>
>> /*
>> * We want to avoid hitting the (re)distributor as much as
>> @@ -378,7 +378,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
>> if (WARN_ON(IS_ERR(map)))
>> return PTR_ERR(map);
>>
>> - timer->map = map;
>> return 0;
>> }
>>
>> @@ -521,8 +520,8 @@ 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->virt_irq);
>> + if (timer->irq.irq)
>> + kvm_vgic_unmap_phys_irq(vcpu, timer->irq.irq);
> thought you agreed to always unmap. Is it an oversight or did you change
> your mind?
I wasn't sure about it. So for the old VGIC implementation having an
illegal IRQ number seems to be fine (just nothing will be found in the
map search), but on the new VGIC it will trigger a BUG_ON, so I was
wondering if we should play safe here and also mimic the current code,
which does this safety check for some reason.
But looking at the (current) callers again, it looks like there is
always "27" passed in here anyways, so I guess we are safe to remove it.
So if no-one intervenes, I will remove the check.
Cheers,
Andre.
> Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>
>
> Cheers
>
> Eric
>> }
>>
>> void kvm_timer_enable(struct kvm *kvm)
>>
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
2016-05-03 16:16 ` Marc Zyngier
@ 2016-05-04 13:30 ` Andre Przywara
2016-05-04 13:54 ` Marc Zyngier
0 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-05-04 13:30 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
On 03/05/16 17:16, Marc Zyngier wrote:
> On 28/04/16 17:45, 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.
>> 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>
>> ---
>> Changelog RFC..v1:
>> - remove outdated comment about the dist_lock
>> - add WARN_ON about LR_STATE not being 0 in maintenance interrupts
>>
>> Changelog v1 .. v2:
>> - inject the IRQ priority into the list register
>>
>> include/linux/irqchip/arm-gic-v3.h | 1 +
>> virt/kvm/arm/vgic/vgic-v3.c | 169 +++++++++++++++++++++++++++++++++++++
>> virt/kvm/arm/vgic/vgic.c | 25 ++++--
>> virt/kvm/arm/vgic/vgic.h | 29 +++++++
>> 4 files changed, 219 insertions(+), 5 deletions(-)
>> create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index d5d798b..56fd2c5 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -275,6 +275,7 @@
>> #define ICH_LR_ACTIVE_BIT (1ULL << 63)
>> #define ICH_LR_PHYS_ID_SHIFT 32
>> #define ICH_LR_PHYS_ID_MASK (0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
>> +#define ICH_LR_PRIORITY_SHIFT 48
>>
>> #define ICH_MISR_EOI (1 << 0)
>> #define ICH_MISR_U (1 << 1)
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> new file mode 100644
>> index 0000000..461229b
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -0,0 +1,169 @@
>> +/*
>> + * 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>
>
> This last line is definitely a (copy-paste) bug. We should never include
> both GIC headers in the same file. Can you please drop that line and
> have the following hunk instead?
>
> +/* These are for GICv2 emulation only */
> +#define GICH_LR_VIRTUALID (0x3ffUL << 0)
> +#define GICH_LR_PHYSID_CPUID_SHIFT (10)
> +#define GICH_LR_PHYSID_CPUID (7UL << GICH_LR_PHYSID_CPUID_SHIFT)
> +#define ICH_LR_VIRTUALID_MASK (BIT_ULL(32) - 1)
> +
What about including those lines (except the last one) in arm-gic-v3.h
then? In fact they describe a property of an _GICv3_ LR, even if it is
only a compatibility feature.
That would be cleaner IMHO than repeating the definitions here in a .c
file and we would automatically get the right definitions by just
including arm-gic-v3.h.
This just compiled fine for me for both the old and new VGIC.
I can send the patch (needs to be a separate patch because it touches
the old VGIC as well) if you agree on that idea.
Cheers,
Andre.
>
> which is similar to what we have in the old implementation, for the
> exact same reason.
>
> Thanks,
>
> M.
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
2016-05-04 13:30 ` Andre Przywara
@ 2016-05-04 13:54 ` Marc Zyngier
2016-05-04 14:21 ` [PATCH] KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h Andre Przywara
0 siblings, 1 reply; 94+ messages in thread
From: Marc Zyngier @ 2016-05-04 13:54 UTC (permalink / raw)
To: linux-arm-kernel
On 04/05/16 14:30, Andre Przywara wrote:
> Hi,
>
> On 03/05/16 17:16, Marc Zyngier wrote:
>> On 28/04/16 17:45, 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.
>>> 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>
>>> ---
>>> Changelog RFC..v1:
>>> - remove outdated comment about the dist_lock
>>> - add WARN_ON about LR_STATE not being 0 in maintenance interrupts
>>>
>>> Changelog v1 .. v2:
>>> - inject the IRQ priority into the list register
>>>
>>> include/linux/irqchip/arm-gic-v3.h | 1 +
>>> virt/kvm/arm/vgic/vgic-v3.c | 169 +++++++++++++++++++++++++++++++++++++
>>> virt/kvm/arm/vgic/vgic.c | 25 ++++--
>>> virt/kvm/arm/vgic/vgic.h | 29 +++++++
>>> 4 files changed, 219 insertions(+), 5 deletions(-)
>>> create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>>>
>>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>>> index d5d798b..56fd2c5 100644
>>> --- a/include/linux/irqchip/arm-gic-v3.h
>>> +++ b/include/linux/irqchip/arm-gic-v3.h
>>> @@ -275,6 +275,7 @@
>>> #define ICH_LR_ACTIVE_BIT (1ULL << 63)
>>> #define ICH_LR_PHYS_ID_SHIFT 32
>>> #define ICH_LR_PHYS_ID_MASK (0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
>>> +#define ICH_LR_PRIORITY_SHIFT 48
>>>
>>> #define ICH_MISR_EOI (1 << 0)
>>> #define ICH_MISR_U (1 << 1)
>>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>>> new file mode 100644
>>> index 0000000..461229b
>>> --- /dev/null
>>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>>> @@ -0,0 +1,169 @@
>>> +/*
>>> + * 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>
>>
>> This last line is definitely a (copy-paste) bug. We should never include
>> both GIC headers in the same file. Can you please drop that line and
>> have the following hunk instead?
>>
>> +/* These are for GICv2 emulation only */
>> +#define GICH_LR_VIRTUALID (0x3ffUL << 0)
>> +#define GICH_LR_PHYSID_CPUID_SHIFT (10)
>> +#define GICH_LR_PHYSID_CPUID (7UL << GICH_LR_PHYSID_CPUID_SHIFT)
>> +#define ICH_LR_VIRTUALID_MASK (BIT_ULL(32) - 1)
>> +
>
> What about including those lines (except the last one) in arm-gic-v3.h
> then? In fact they describe a property of an _GICv3_ LR, even if it is
> only a compatibility feature.
> That would be cleaner IMHO than repeating the definitions here in a .c
> file and we would automatically get the right definitions by just
> including arm-gic-v3.h.
>
> This just compiled fine for me for both the old and new VGIC.
> I can send the patch (needs to be a separate patch because it touches
> the old VGIC as well) if you agree on that idea.
Sure, send the patch.
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH] KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h
2016-05-04 13:54 ` Marc Zyngier
@ 2016-05-04 14:21 ` Andre Przywara
2016-05-04 14:28 ` Marc Zyngier
0 siblings, 1 reply; 94+ messages in thread
From: Andre Przywara @ 2016-05-04 14:21 UTC (permalink / raw)
To: linux-arm-kernel
As (some) GICv3 hosts can emulate a GICv2, some GICv2 specific masks
for the list register definition also apply to GICv3 LRs.
At the moment we have those definitions in the KVM VGICv3
implementation, so let's move them into the GICv3 header file to
have them automatically defined.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
... and then just remove the #include <arm-gic.h> from vgic/vgic-v3.c.
Does that make sense?
Cheers,
Andre.
include/linux/irqchip/arm-gic-v3.h | 5 +++++
virt/kvm/arm/vgic-v3.c | 8 +-------
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 56fd2c5..35e93cf 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -277,6 +277,11 @@
#define ICH_LR_PHYS_ID_MASK (0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
#define ICH_LR_PRIORITY_SHIFT 48
+/* These are for GICv2 emulation only */
+#define GICH_LR_VIRTUALID (0x3ffUL << 0)
+#define GICH_LR_PHYSID_CPUID_SHIFT (10)
+#define GICH_LR_PHYSID_CPUID (7UL << GICH_LR_PHYSID_CPUID_SHIFT)
+
#define ICH_MISR_EOI (1 << 0)
#define ICH_MISR_U (1 << 1)
diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
index 999bdc6..9c5cfc2 100644
--- a/virt/kvm/arm/vgic-v3.c
+++ b/virt/kvm/arm/vgic-v3.c
@@ -31,12 +31,6 @@
#include <asm/kvm_asm.h>
#include <asm/kvm_mmu.h>
-/* These are for GICv2 emulation only */
-#define GICH_LR_VIRTUALID (0x3ffUL << 0)
-#define GICH_LR_PHYSID_CPUID_SHIFT (10)
-#define GICH_LR_PHYSID_CPUID (7UL << GICH_LR_PHYSID_CPUID_SHIFT)
-#define ICH_LR_VIRTUALID_MASK (BIT_ULL(32) - 1)
-
static u32 ich_vtr_el2;
static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
@@ -45,7 +39,7 @@ static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr];
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
- lr_desc.irq = val & ICH_LR_VIRTUALID_MASK;
+ lr_desc.irq = val & ICH_LR_VIRTUAL_ID_MASK;
else
lr_desc.irq = val & GICH_LR_VIRTUALID;
--
2.7.3
^ permalink raw reply related [flat|nested] 94+ messages in thread
* [PATCH] KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h
2016-05-04 14:21 ` [PATCH] KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h Andre Przywara
@ 2016-05-04 14:28 ` Marc Zyngier
0 siblings, 0 replies; 94+ messages in thread
From: Marc Zyngier @ 2016-05-04 14:28 UTC (permalink / raw)
To: linux-arm-kernel
On 04/05/16 15:21, Andre Przywara wrote:
> As (some) GICv3 hosts can emulate a GICv2, some GICv2 specific masks
> for the list register definition also apply to GICv3 LRs.
> At the moment we have those definitions in the KVM VGICv3
> implementation, so let's move them into the GICv3 header file to
> have them automatically defined.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
M.
> ---
> ... and then just remove the #include <arm-gic.h> from vgic/vgic-v3.c.
>
> Does that make sense?
Definitely.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 14/54] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
2016-05-03 23:46 ` Tom Hanson
@ 2016-05-05 11:24 ` Andre Przywara
2016-05-05 14:43 ` Marc Zyngier
2016-05-05 16:34 ` Tom Hanson
0 siblings, 2 replies; 94+ messages in thread
From: Andre Przywara @ 2016-05-05 11:24 UTC (permalink / raw)
To: linux-arm-kernel
Hi Tom,
thanks for looking at the patches!
On 04/05/16 00:46, Tom Hanson wrote:
> On 04/28/2016 10:45 AM, Andre Przywara wrote:
> ...
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index fb45537..92b78a0 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -19,8 +19,31 @@
> ...
>> +/*
>> + * 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);
>> + */
>
> The code would be safer and easier to maintain in the long run if there
> were functions provided which implement these 2 rules. Something along
> the line of:
>
> void vgic_lock_aplist_irq(spinlock_t ap_list_lock, spinlock_t irq_lock){
> spin_lock(ap_list_lock);
> spin_lock(irq_lock);
> }
The idea isn't too bad indeed.
I see that we could use that in vgic_queue_irq_unlock() and
vgic_mmio_write_sactive().
But as Marc mentioned in a conversation yesterday we will have a mixture
of wrapped locks and open coded lock sequences. See for instance
vgic_prune_ap_list(), where we have the sequence, but we can't use
vgic_lock_aplist_irq() because the IRQ lock is taken inside the loop
while the ap_list_lock is taken once outside of it.
Marc, Christoffer, what is your opinion here?
> and (borrowing from patch 16/54):
>
> void vgic_lock_cpu_aplist_pair(struct kvm_vcpu *vcpu1, struct kvm_vcpu
> *vcpu2){
> struct kvm_vcpu *vcpuA, *vcpuB;
> /*
> * Ensure locking order by always locking the smallest
> * ID first.
> */
> if (vcpu1->vcpu_id < vcpu2->vcpu_id) {
> vcpuA = vcpu1;
> vcpuB = vcpu2;
> } else {
> vcpuA = vcpu2;
> vcpuB = vcpu1;
> }
>
> spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> }
I am not sure this is worth it. We have exactly one user of this
sequence, so I'd rather keep it and the comments there.
Also the use case is probably confined to the core VGIC code.
Cheers,
Andre.
>
> With, of course the matching unlock functions.
>
> Then, as long as new code calls the correct function, the order is
> always correct. Easy to write, easy to review. And beats the heck out
> of chasing a deadlock at some point in the future.
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 14/54] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
2016-05-05 11:24 ` Andre Przywara
@ 2016-05-05 14:43 ` Marc Zyngier
2016-05-05 16:34 ` Tom Hanson
1 sibling, 0 replies; 94+ messages in thread
From: Marc Zyngier @ 2016-05-05 14:43 UTC (permalink / raw)
To: linux-arm-kernel
On 05/05/16 12:24, Andre Przywara wrote:
> Hi Tom,
>
> thanks for looking at the patches!
>
> On 04/05/16 00:46, Tom Hanson wrote:
>> On 04/28/2016 10:45 AM, Andre Przywara wrote:
>> ...
>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>>> index fb45537..92b78a0 100644
>>> --- a/virt/kvm/arm/vgic/vgic.c
>>> +++ b/virt/kvm/arm/vgic/vgic.c
>>> @@ -19,8 +19,31 @@
>> ...
>>> +/*
>>> + * 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);
>>> + */
>>
>> The code would be safer and easier to maintain in the long run if there
>> were functions provided which implement these 2 rules. Something along
>> the line of:
>>
>> void vgic_lock_aplist_irq(spinlock_t ap_list_lock, spinlock_t irq_lock){
>> spin_lock(ap_list_lock);
>> spin_lock(irq_lock);
>> }
>
> The idea isn't too bad indeed.
> I see that we could use that in vgic_queue_irq_unlock() and
> vgic_mmio_write_sactive().
> But as Marc mentioned in a conversation yesterday we will have a mixture
> of wrapped locks and open coded lock sequences. See for instance
> vgic_prune_ap_list(), where we have the sequence, but we can't use
> vgic_lock_aplist_irq() because the IRQ lock is taken inside the loop
> while the ap_list_lock is taken once outside of it.
>
> Marc, Christoffer, what is your opinion here?
I don't mind switching to these more "high level" primitives, but I'm
slightly worried that whoever starts using them will not consider that
they are quite heavy and not always required.
But maybe it is worth a try.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 16/54] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
2016-04-28 16:45 ` [PATCH v2 16/54] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework Andre Przywara
@ 2016-05-05 16:23 ` Tom Hanson
2016-05-05 16:44 ` Tom Hanson
0 siblings, 1 reply; 94+ messages in thread
From: Tom Hanson @ 2016-05-05 16:23 UTC (permalink / raw)
To: linux-arm-kernel
On 04/28/2016 10:45 AM, Andre Przywara wrote:
...
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 4fb20fd..a656a12e5 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
...
> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> +{
...
> + /* This interrupt looks like it has to be migrated. */
> +
> + spin_unlock(&irq->irq_lock);
> + spin_unlock(&vgic_cpu->ap_list_lock);
If using the suggested (but not provided) higher level function from patch 14 this could be:
vgic_unlock_aplist_irq(, spinlock_t irq);
> +
> + /*
> + * 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);
And this whole block could be replaced by:
vgic_lock_cpu_aplist_pair(vcpuA, vcpuB)
> + spin_lock(&irq->irq_lock);
...
> + spin_unlock(&irq->irq_lock);
> + spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> + spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
And this could be:
vgic_unlock_cpu_aplist_pair(vcpuA, vcpuB)
> + goto retry;
> + }
> +
> + spin_unlock(&vgic_cpu->ap_list_lock);
> +}
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 14/54] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
2016-05-05 11:24 ` Andre Przywara
2016-05-05 14:43 ` Marc Zyngier
@ 2016-05-05 16:34 ` Tom Hanson
1 sibling, 0 replies; 94+ messages in thread
From: Tom Hanson @ 2016-05-05 16:34 UTC (permalink / raw)
To: linux-arm-kernel
On 05/05/2016 05:24 AM, Andre Przywara wrote:
> Hi Tom,
>
> thanks for looking at the patches!
>
You're quite welcome. It's a great way to spin-up.
> The idea isn't too bad indeed.
> I see that we could use that in vgic_queue_irq_unlock() and
> vgic_mmio_write_sactive().
> But as Marc mentioned in a conversation yesterday we will have a mixture
> of wrapped locks and open coded lock sequences. See for instance
> vgic_prune_ap_list(), where we have the sequence, but we can't use
> vgic_lock_aplist_irq() because the IRQ lock is taken inside the loop
> while the ap_list_lock is taken once outside of it.
Agreed. I looked at a few places where it wouldn't work. Definitely not a blanket solution but every little bit helps, especially if it helps avoid a bug such as a deadlock that may take hours to track down. Been there, done that. :-)
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 16/54] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
2016-05-05 16:23 ` Tom Hanson
@ 2016-05-05 16:44 ` Tom Hanson
0 siblings, 0 replies; 94+ messages in thread
From: Tom Hanson @ 2016-05-05 16:44 UTC (permalink / raw)
To: linux-arm-kernel
On 05/05/2016 10:23 AM, Tom Hanson wrote:
> On 04/28/2016 10:45 AM, Andre Przywara wrote:
>
> ...
>
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 4fb20fd..a656a12e5 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>
> ...
>> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
>> +{
>
> ...
>
>> + /* This interrupt looks like it has to be migrated. */
>> +
>> + spin_unlock(&irq->irq_lock);
>> + spin_unlock(&vgic_cpu->ap_list_lock);
>
> If using the suggested (but not provided) higher level function from patch 14 this could be:
> vgic_unlock_aplist_irq(, spinlock_t irq);
Oh, bother. That should be:
vgic_unlock_aplist_irq(vgic_cpu->ap_list_lock, irq->irq_lock);
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 26/54] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
2016-04-28 16:45 ` [PATCH v2 26/54] KVM: arm/arm64: vgic-new: Add ACTIVE " Andre Przywara
@ 2016-05-05 16:48 ` Tom Hanson
0 siblings, 0 replies; 94+ messages in thread
From: Tom Hanson @ 2016-05-05 16:48 UTC (permalink / raw)
To: linux-arm-kernel
On 04/28/2016 10:45 AM, Andre Przywara wrote:
...
> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> + gpa_t addr, unsigned int len,
> + unsigned long val)
...
> + spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> + spin_lock(&irq->irq_lock);
If using the suggested higher level function from patch 14 this could be:
vgic_lock_aplist_irq(&vcpu->arch.vgic_cpu.ap_list_lock, &irq->irq_lock);
> +
> + /*
> + * Recheck after dropping the IRQ lock to see if we should
> + * still care about queueing it.
> + */
> + if (irq->active || irq->vcpu) {
> + irq->active = true;
> +
> + spin_unlock(&irq->irq_lock);
> + spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
And this could be:
vgic_unlock_aplist_irq(&vcpu->arch.vgic_cpu.ap_list_lock, &irq->irq_lock);
> +
> + continue;
> + }
> +
> + /* Did the target VCPU change while we had the lock dropped? */
> + if (vcpu != irq->target_vcpu) {
> + spin_unlock(&irq->irq_lock);
> + spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
And this could be:
vgic_unlock_aplist_irq(&vcpu->arch.vgic_cpu.ap_list_lock, &irq->irq_lock);
> +
> + goto retry;
> + }
> +
> + /* Now queue the IRQ to the VCPU's ap_list. */
> + list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> + irq->vcpu = vcpu;
> +
> + irq->active = true;
> +
> + spin_unlock(&irq->irq_lock);
> + spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
And this could be:
vgic_unlock_aplist_irq(&vcpu->arch.vgic_cpu.ap_list_lock, &irq->irq_lock);
> +
> + kvm_vcpu_kick(vcpu);
> + }
> +}
> +
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
2016-04-28 16:45 ` [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 " Andre Przywara
2016-05-03 16:16 ` Marc Zyngier
@ 2016-05-05 17:04 ` Tom Hanson
1 sibling, 0 replies; 94+ messages in thread
From: Tom Hanson @ 2016-05-05 17:04 UTC (permalink / raw)
To: linux-arm-kernel
On 04/28/2016 10:45 AM, Andre Przywara wrote:
...
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> new file mode 100644
> index 0000000..461229b
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
...
> +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 */
If truly required that ap_list_lock already be locked, then the code should enforce it. At least in dev mode. Maybe:
DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->ap_list_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 = irq->intid;
> +
Similarly, if required then the code should enforce it.
DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
...
^ permalink raw reply [flat|nested] 94+ messages in thread
* [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
2016-05-02 16:13 ` Eric Auger
@ 2016-05-05 17:55 ` Andre Przywara
0 siblings, 0 replies; 94+ messages in thread
From: Andre Przywara @ 2016-05-05 17:55 UTC (permalink / raw)
To: linux-arm-kernel
Hi Eric,
On 02/05/16 17:13, Eric Auger wrote:
> Hi Andre,
>
> Some minor comments below.
> On 04/28/2016 06:45 PM, Andre Przywara wrote:
>> Create a new file called vgic-mmio-v3.c and describe the GICv3
>> distributor and redistributor registers there.
>> 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 provide a function to deal with the registration of the two
>> separate redistributor frames per VCPU.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - adapt to new MMIO registration approach:
>> register one device for the distributor and two for each VCPU
>> - implement special handling for private interrupts
>> - remove empty stub functions
>> - make IGROUPR return RAO
>>
>> Changelog v1 .. v2:
>> - adapt to new framework, introduce vgic-mmio-v3.c
>> - remove userland register access functions (for now)
>> - precompute .len when describing a VGIC register
>> - add missed pointer incrementation on registering redist regions
>> - replace _nyi stub functions with raz/wi versions
>>
>> virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>> virt/kvm/arm/vgic/vgic-mmio.c | 5 +
>> virt/kvm/arm/vgic/vgic-mmio.h | 2 +
>> virt/kvm/arm/vgic/vgic.h | 3 +
>> 4 files changed, 201 insertions(+)
>> create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> new file mode 100644
>> index 0000000..c6765d4
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -0,0 +1,191 @@
>> +/*
>> + * VGICv3 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/irqchip/arm-gic-v3.h>
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <kvm/iodev.h>
>> +#include <kvm/vgic/vgic.h>
>> +
>> +#include <asm/kvm_emulate.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic-mmio.h"
>> +
>> +/*
>> + * 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(off, read_ops, write_ops, bpi) \
>> + { \
>> + .reg_offset = off, \
>> + .bits_per_irq = bpi, \
>> + .len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
>> + .read = vgic_mmio_read_raz, \
>> + .write = vgic_mmio_write_wi, \
>> + }, { \
>> + .reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
>> + .bits_per_irq = bpi, \
>> + .len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8, \
>> + .read = read_ops, \
>> + .write = write_ops, \
>> + }
>> +
>> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
>> + REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>> + vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>> + REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>> + vgic_mmio_read_rao, 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),
>> + REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>> + vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
>> + REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>> + vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
> would add a comment to say this corresponds to RD_base frame, to use the
> same terminology as the spec. IHI0069B.
>> +static const struct vgic_register_region vgic_v3_redist_registers[] = {
>> + REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>> + vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> + REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>> + vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> + REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>> + vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> + REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>> + vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> + REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>> + vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> + REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
>> + vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
> same as above: SGI_base frame. Used terminology was a bit misleading for
> me since this is also part of redist, 2d frame.
I took the freedom to just replace the variable names with
vgic_v3_rdbase_registers and vgic_v3_sgibase_registers, respectively.
Hope that does the trick for you as well.
>> +static const struct vgic_register_region vgic_v3_private_registers[] = {
>> + REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
>> + vgic_mmio_read_rao, 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),
>> +};
>> +
>> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
>> +{
>> + dev->regions = vgic_v3_dist_registers;
>> + dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
>> +
>> + kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
>> +
>> + return SZ_64K;
>> +}
>> +
>> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>> +{
>> + int nr_vcpus = atomic_read(&kvm->online_vcpus);
>> + struct kvm_vcpu *vcpu;
>> + struct vgic_io_device *devices, *device;
>> + int c, ret = 0;
>> +
>> + devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
>> + GFP_KERNEL);
>> + if (!devices)
>> + return -ENOMEM;
>> +
>> + device = devices;
>> + kvm_for_each_vcpu(c, vcpu, kvm) {
>> + kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> + device->base_addr = redist_base_address;
>> + device->regions = vgic_v3_redist_registers;
>> + device->nr_regions = ARRAY_SIZE(vgic_v3_redist_registers);
>> + device->redist_vcpu = vcpu;
>> +
>> + mutex_lock(&kvm->slots_lock);
>> + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> + redist_base_address,
>> + SZ_64K, &device->dev);
>> + mutex_unlock(&kvm->slots_lock);
>> +
>> + if (ret)
>> + break;
>> +
>> + device++;
>> + kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> + device->base_addr = redist_base_address + SZ_64K;
>> + device->regions = vgic_v3_private_registers;
>> + device->nr_regions = ARRAY_SIZE(vgic_v3_private_registers);
>> + device->redist_vcpu = vcpu;
>> +
>> + mutex_lock(&kvm->slots_lock);
>> + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> + redist_base_address + SZ_64K,
>> + SZ_64K, &device->dev);
>> + mutex_unlock(&kvm->slots_lock);
>> + if (ret) {
>> + kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> + &devices[c * 2].dev);
>> + break;
>> + }
>> + device++;
>> + redist_base_address += 2 * SZ_64K;
>> + }
>> +
>> + if (ret) {
>> + for (c--; c >= 0; c--) {
>> + kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> + &devices[c * 2].dev);
>> + kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> + &devices[c * 2 + 1].dev);
>> + }
>> + kfree(devices);
>> + } else {
>> + kvm->arch.vgic.redist_iodevs = devices;
>> + }
>> +
>> + return ret;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index bf4278c..80d977e 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -502,6 +502,11 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>> case VGIC_V2:
>> len = vgic_v2_init_dist_iodev(io_device);
>> break;
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> + case VGIC_V3:
>> + len = vgic_v3_init_dist_iodev(io_device);
>> + break;
>> +#endif
>> default:
>> BUG_ON(1);
>> }
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
>> index 884eb71..3585ac6 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -123,4 +123,6 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>
>> unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>
>> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
>> +
>> #endif
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 1ab7d97..6fe07df 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -61,6 +61,9 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
>> static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>> {
>> }
>> +
>> #endif
>>
>> +void kvm_register_vgic_device(unsigned long type);
> I don't think this relates to this patch.
Eek, good catch.
> Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>
Merci!
Andre.
^ permalink raw reply [flat|nested] 94+ messages in thread
end of thread, other threads:[~2016-05-05 17:55 UTC | newest]
Thread overview: 94+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-04-28 16:45 [PATCH v2 00/54] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
2016-04-28 16:45 ` [PATCH v2 01/54] KVM: arm/arm64: vgic: streamline vgic_update_irq_pending() interface Andre Przywara
2016-04-28 16:45 ` [PATCH v2 02/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_inject_mapped_irq() Andre Przywara
2016-04-28 16:45 ` [PATCH v2 03/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_map_is_active() Andre Przywara
2016-04-28 16:45 ` [PATCH v2 04/54] KVM: arm/arm64: vgic: avoid map in kvm_vgic_unmap_phys_irq() Andre Przywara
2016-04-28 16:45 ` [PATCH v2 05/54] KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map Andre Przywara
2016-05-03 12:15 ` Marc Zyngier
2016-04-28 16:45 ` [PATCH v2 06/54] KVM: arm/arm64: arch_timer: Remove irq_phys_map Andre Przywara
2016-05-02 16:44 ` Eric Auger
2016-05-04 10:37 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 07/54] KVM: arm/arm64: vgic: Remove irq_phys_map from interface Andre Przywara
2016-05-03 22:22 ` Tom Hanson
2016-04-28 16:45 ` [PATCH v2 08/54] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr Andre Przywara
2016-04-28 16:45 ` [PATCH v2 09/54] KVM: arm/arm64: Fix MMIO emulation data handling Andre Przywara
2016-04-28 16:45 ` [PATCH v2 10/54] KVM: arm/arm64: Export mmio_read/write_bus Andre Przywara
2016-04-28 16:45 ` [PATCH v2 11/54] KVM: arm/arm64: pmu: abstract access to number of SPIs Andre Przywara
2016-04-28 16:45 ` [PATCH v2 12/54] KVM: arm/arm64: vgic-new: Add data structure definitions Andre Przywara
2016-04-28 16:45 ` [PATCH v2 13/54] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance Andre Przywara
2016-04-28 16:45 ` [PATCH v2 14/54] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection Andre Przywara
2016-05-03 23:46 ` Tom Hanson
2016-05-05 11:24 ` Andre Przywara
2016-05-05 14:43 ` Marc Zyngier
2016-05-05 16:34 ` Tom Hanson
2016-04-28 16:45 ` [PATCH v2 15/54] KVM: arm/arm64: vgic-new: Add IRQ sorting Andre Przywara
2016-04-28 16:45 ` [PATCH v2 16/54] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework Andre Przywara
2016-05-05 16:23 ` Tom Hanson
2016-05-05 16:44 ` Tom Hanson
2016-04-28 16:45 ` [PATCH v2 17/54] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend Andre Przywara
2016-05-02 12:16 ` Marc Zyngier
2016-05-03 8:26 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 " Andre Przywara
2016-05-03 16:16 ` Marc Zyngier
2016-05-04 13:30 ` Andre Przywara
2016-05-04 13:54 ` Marc Zyngier
2016-05-04 14:21 ` [PATCH] KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h Andre Przywara
2016-05-04 14:28 ` Marc Zyngier
2016-05-05 17:04 ` [PATCH v2 18/54] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend Tom Hanson
2016-04-28 16:45 ` [PATCH v2 19/54] KVM: arm/arm64: vgic-new: Implement Andre Przywara
2016-05-02 12:24 ` Eric Auger
2016-05-03 8:26 ` Andre Przywara
2016-04-28 16:45 ` [PATCH v2 20/54] KVM: arm/arm64: vgic-new: Add MMIO handling framework Andre Przywara
2016-04-28 16:45 ` [PATCH v2 21/54] KVM: arm/arm64: vgic-new: Add GICv2 " Andre Przywara
2016-05-03 15:32 ` Marc Zyngier
2016-04-28 16:45 ` [PATCH v2 22/54] KVM: arm/arm64: vgic-new: Export register access interface Andre Przywara
2016-04-28 16:45 ` [PATCH v2 23/54] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers Andre Przywara
2016-04-28 16:45 ` [PATCH v2 24/54] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers Andre Przywara
2016-04-28 16:45 ` [PATCH v2 25/54] KVM: arm/arm64: vgic-new: Add PENDING " Andre Przywara
2016-04-28 16:45 ` [PATCH v2 26/54] KVM: arm/arm64: vgic-new: Add ACTIVE " Andre Przywara
2016-05-05 16:48 ` Tom Hanson
2016-04-28 16:45 ` [PATCH v2 27/54] KVM: arm/arm64: vgic-new: Add PRIORITY " Andre Przywara
2016-04-28 16:45 ` [PATCH v2 28/54] KVM: arm/arm64: vgic-new: Add CONFIG " Andre Przywara
2016-04-28 16:45 ` [PATCH v2 29/54] KVM: arm/arm64: vgic-new: Add TARGET " Andre Przywara
2016-04-28 16:45 ` [PATCH v2 30/54] KVM: arm/arm64: vgic-new: Add SGIR register handler Andre Przywara
2016-04-28 16:45 ` [PATCH v2 31/54] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers Andre Przywara
2016-04-28 16:45 ` [PATCH v2 32/54] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Andre Przywara
2016-04-29 14:04 ` Vladimir Murzin
2016-04-29 14:22 ` Vladimir Murzin
2016-05-02 8:38 ` Christoffer Dall
2016-05-02 16:13 ` Eric Auger
2016-05-05 17:55 ` Andre Przywara
2016-05-03 15:34 ` Marc Zyngier
2016-04-28 16:45 ` [PATCH v2 33/54] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers Andre Przywara
2016-04-28 16:45 ` [PATCH v2 34/54] KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and TYPER handler Andre Przywara
2016-04-28 16:45 ` [PATCH v2 35/54] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler Andre Przywara
2016-04-28 16:45 ` [PATCH v2 36/54] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers Andre Przywara
2016-04-28 16:45 ` [PATCH v2 37/54] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler Andre Przywara
2016-04-28 16:45 ` [PATCH v2 38/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration Andre Przywara
2016-04-28 16:45 ` [PATCH v2 39/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS Andre Przywara
2016-04-28 16:45 ` [PATCH v2 40/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL Andre Przywara
2016-04-28 16:46 ` [PATCH v2 41/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR Andre Przywara
2016-04-28 16:46 ` [PATCH v2 42/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers Andre Przywara
2016-05-03 9:59 ` Marc Zyngier
2016-05-03 10:09 ` Andre Przywara
2016-05-03 10:12 ` Marc Zyngier
2016-05-03 10:16 ` Marc Zyngier
2016-05-03 16:07 ` [PATCH] KVM: arm/arm64: new-vgic: add proper GICv2 CPU interface userland access Andre Przywara
2016-05-03 17:00 ` Marc Zyngier
2016-05-03 17:59 ` Marc Zyngier
2016-04-28 16:46 ` [PATCH v2 43/54] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr Andre Przywara
2016-04-28 16:46 ` [PATCH v2 44/54] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers Andre Przywara
2016-04-28 16:46 ` [PATCH v2 45/54] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors Andre Przywara
2016-04-28 16:46 ` [PATCH v2 46/54] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access Andre Przywara
2016-05-03 10:21 ` Marc Zyngier
2016-04-28 16:46 ` [PATCH v2 47/54] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init Andre Przywara
2016-05-03 15:02 ` Marc Zyngier
2016-05-03 15:35 ` Marc Zyngier
2016-04-28 16:46 ` [PATCH v2 48/54] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create Andre Przywara
2016-04-28 16:46 ` [PATCH v2 49/54] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init Andre Przywara
2016-04-28 16:46 ` [PATCH v2 50/54] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources Andre Przywara
2016-05-03 10:47 ` Marc Zyngier
2016-04-28 16:46 ` [PATCH v2 51/54] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable Andre Przywara
2016-04-28 16:46 ` [PATCH v2 52/54] KVM: arm/arm64: vgic-new: Wire up irqfd injection Andre Przywara
2016-04-28 16:46 ` [PATCH v2 53/54] KVM: arm/arm64: vgic-new: implement mapped IRQ handling Andre Przywara
2016-04-28 16:46 ` [PATCH v2 54/54] KVM: arm/arm64: vgic-new: enable build Andre Przywara
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).