* [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-04-15 17:11 Andre Przywara
2016-04-15 17:11 ` [PATCH 01/45] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr Andre Przywara
` (45 more replies)
0 siblings, 46 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
this is a rework of the new VGIC series.
Many thanks to all reviewers, especially Christoffer.
Major changes include a dependency on a new, separate arch_timer rework
series [1], a total rework of the MMIO dispatching, which now uses much
less kvm_io_bus devices, the proper handling of enabling and disabling
the distributor and the much more elaborate handling of activating an
IRQ via the MMIO interface.
Also the patches have been rearranged a bit in the world switch area
and for the GICv3 MMIO handling to be more logical and avoid stub
functions that get populated only later.
Minor changes are:
- removal of vgic_cpu->nr_lr in favour of kvm_vgic_global_state
- refinements in the virtual IRQ queueing function
- introduction of a separate vgic_clear_lr() function
- the removal of the vgic_v[23]_irq_change_affinity functions
- caring about SGI injection on SGIPENDR writes
- removing locks for atomic reads in the MMIO handlers
- removal of ITS stub functions
- introducing vgic_irq_is_sgi()
- many comment fixes
The simple arch_timer rework in the RFC series has been replaced with
a separate rework series [1]. Also there is new preparatory patch from
Christoffer which gets rid of reading the number of LRs from the
vgic_cpu structure. The MMIO data write back fix has also been replaced
with a more sophisticated version.
I refrained from merging vgic_v[23]_populate_lr() and
vgic_v[23]_process_maintenance(), respectively. Having taken a closer
look it does not appear worthwhile to me to unify the implementations.
Topics which I couldn't manage to address due to timing restraints are:
- proper PHYS_CPUID masking when populating GICv2 LRs
- proper handling of priorites on injection, also filtering(?)
- proper endianess handling in the MMIO framework (not in the VGIC)
- handling corner cases when clearing the active state via MMIO
- cleanup of register region description with new MMIO framework
This series is now based on v4.6-rc3 plus the arch_timer rework[1].
A git tree containing this series and the prerequisites can be found on
linux-arm.org:
git://linux-arm.org/linux-ap.git branch: vgic-new/v1
http://www.linux-arm.org/git?p=linux-ap.git;a=log;h=refs/heads/vgic-new/v1
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 data
structure, which holds all information about a virtual interrupt.
Interruts which should be injected are hold in a per-VCPU list, this
make the entry/exit path much more efficient. Also the new structure
allows to have more fine grained locking - per IRQ and per VCPU -
getting rid of the global distributor lock.
As a result of the new design ITS emulation fits in more nicely, the
respective code will be provided as a follow-up series.
This series implements the same feature set as the existing emulation,
as a goodie we now implement priorities correctly.
To allow an easy transition with good test coverage, but still maintain
stability, both implementations live side by side, selectable via a
Kconfig option. The default is the new implementation.
If this code proves to be reliable, we will later remove the current
implementation with an extra patch set.
Please have a look at the series, review it and give the code some
serious testing (and possibly debugging). All feedback is appreciated.
Cheers,
Andre.
[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2016-April/422580.html
Andre Przywara (24):
KVM: arm/arm64: pmu: abstract access to number of SPIs
KVM: arm/arm64: vgic-new: Add MMIO handling framework
KVM: arm/arm64: vgic-new: Export register access interface
KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
KVM: arm/arm64: vgic-new: Add PENDING registers handlers
KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
KVM: arm/arm64: vgic-new: Add TARGET registers handlers
KVM: arm/arm64: vgic-new: Add SGIR register handler
KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR, TYPER handlers
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 (6):
KVM: arm/arm64: Get rid of vgic_cpu->nr_lr
KVM: arm/arm64: Fix MMIO emulation data handling
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
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 (3):
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
arch/arm/kvm/Kconfig | 7 +
arch/arm/kvm/Makefile | 10 +
arch/arm/kvm/mmio.c | 14 +-
arch/arm64/kvm/Kconfig | 7 +
arch/arm64/kvm/Makefile | 10 +
include/kvm/arm_vgic.h | 10 +-
include/kvm/vgic/vgic.h | 250 +++++++
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 | 19 +-
virt/kvm/arm/vgic/vgic-v2.c | 355 +++++++++
virt/kvm/arm/vgic/vgic-v3.c | 333 +++++++++
virt/kvm/arm/vgic/vgic.c | 617 +++++++++++++++
virt/kvm/arm/vgic/vgic.h | 138 ++++
virt/kvm/arm/vgic/vgic_init.c | 446 +++++++++++
virt/kvm/arm/vgic/vgic_irqfd.c | 51 ++
virt/kvm/arm/vgic/vgic_kvm_device.c | 522 +++++++++++++
virt/kvm/arm/vgic/vgic_mmio.c | 1411 +++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic_mmio.h | 53 ++
20 files changed, 4242 insertions(+), 34 deletions(-)
create mode 100644 include/kvm/vgic/vgic.h
create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
create mode 100644 virt/kvm/arm/vgic/vgic.c
create mode 100644 virt/kvm/arm/vgic/vgic.h
create mode 100644 virt/kvm/arm/vgic/vgic_init.c
create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
create mode 100644 virt/kvm/arm/vgic/vgic_kvm_device.c
create mode 100644 virt/kvm/arm/vgic/vgic_mmio.c
create mode 100644 virt/kvm/arm/vgic/vgic_mmio.h
--
2.7.3
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 01/45] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 02/45] KVM: arm/arm64: Fix MMIO emulation data handling Andre Przywara
` (44 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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>
---
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] 60+ messages in thread
* [PATCH 02/45] KVM: arm/arm64: Fix MMIO emulation data handling
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
2016-04-15 17:11 ` [PATCH 01/45] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 03/45] KVM: arm/arm64: pmu: abstract access to number of SPIs Andre Przywara
` (43 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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>
---
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] 60+ messages in thread
* [PATCH 03/45] KVM: arm/arm64: pmu: abstract access to number of SPIs
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
2016-04-15 17:11 ` [PATCH 01/45] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr Andre Przywara
2016-04-15 17:11 ` [PATCH 02/45] KVM: arm/arm64: Fix MMIO emulation data handling Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions Andre Przywara
` (42 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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..472d556 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 b5754c6..0b2c1fa 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -476,7 +476,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
* the interrupt number is the same for all vcpus, while as an
* SPI it must be a separate number per vcpu.
*/
- if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
+ if (irq < VGIC_NR_SGIS || !vgic_valid_spi(vcpu->kvm, irq) ||
!irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
return -EINVAL;
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (2 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 03/45] KVM: arm/arm64: pmu: abstract access to number of SPIs Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance Andre Przywara
` (41 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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
---
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 472d556..2da8362 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..2461852
--- /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 */
+ u32 enabled;
+
+ struct vgic_irq *spis;
+};
+
+struct vgic_v2_cpu_if {
+ u32 vgic_hcr;
+ u32 vgic_vmcr;
+ u32 vgic_misr; /* Saved only */
+ u64 vgic_eisr; /* Saved only */
+ u64 vgic_elrsr; /* Saved only */
+ u32 vgic_apr;
+ u32 vgic_lr[VGIC_V2_MAX_LRS];
+};
+
+struct vgic_v3_cpu_if {
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+ u32 vgic_hcr;
+ u32 vgic_vmcr;
+ u32 vgic_sre; /* Restored only, change ignored */
+ u32 vgic_misr; /* Saved only */
+ u32 vgic_eisr; /* Saved only */
+ u32 vgic_elrsr; /* Saved only */
+ u32 vgic_ap0r[4];
+ u32 vgic_ap1r[4];
+ u64 vgic_lr[VGIC_V3_MAX_LRS];
+#endif
+};
+
+struct vgic_cpu {
+ /* CPU vif control registers for world switch */
+ union {
+ struct vgic_v2_cpu_if vgic_v2;
+ struct vgic_v3_cpu_if vgic_v3;
+ };
+
+ 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] 60+ messages in thread
* [PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (3 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-25 16:15 ` Andrew Jones
2016-04-15 17:11 ` [PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection Andre Przywara
` (40 subsequent siblings)
45 siblings, 1 reply; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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] 60+ messages in thread
* [PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (4 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 07/45] KVM: arm/arm64: vgic-new: Add IRQ sorting Andre Przywara
` (39 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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
---
include/kvm/vgic/vgic.h | 3 +
virt/kvm/arm/vgic/vgic.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 1 +
3 files changed, 201 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2461852..dd884ba 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..60c03f2 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,177 @@ 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 void vgic_update_irq_pending(struct kvm *kvm, struct kvm_vcpu *vcpu,
+ u32 intid, bool level)
+{
+ struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, intid);
+
+ trace_vgic_update_irq_pending(vcpu->vcpu_id, intid, level);
+
+ spin_lock(&irq->irq_lock);
+
+ if (!vgic_validate_injection(irq, level)) {
+ /* Nothing to see here, move along... */
+ spin_unlock(&irq->irq_lock);
+ return;
+ }
+
+ if (irq->config == VGIC_CONFIG_LEVEL) {
+ irq->line_level = level;
+ irq->pending = level || irq->soft_pending;
+ } else {
+ irq->pending = true;
+ }
+
+ vgic_queue_irq_unlock(kvm, irq);
+}
+
+/**
+ * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
+ * @kvm: The VM structure pointer
+ * @cpuid: The CPU for PPIs
+ * @intid: The INTID to inject a new state to.
+ * @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)
+{
+ struct kvm_vcpu *vcpu;
+
+ vcpu = kvm_get_vcpu(kvm, cpuid);
+ vgic_update_irq_pending(kvm, vcpu, intid, level);
+ return 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 61b8d22..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] 60+ messages in thread
* [PATCH 07/45] KVM: arm/arm64: vgic-new: Add IRQ sorting
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (5 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 08/45] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework Andre Przywara
` (38 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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 60c03f2..0b1dadf 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] 60+ messages in thread
* [PATCH 08/45] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (6 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 07/45] KVM: arm/arm64: vgic-new: Add IRQ sorting Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend Andre Przywara
` (37 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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 dd884ba..97c919c 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 0b1dadf..65fa9ac 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -293,3 +293,203 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
vgic_update_irq_pending(kvm, vcpu, intid, level);
return 0;
}
+
+/**
+ * vgic_prune_ap_list - Remove non-relevant interrupts from the list
+ *
+ * @vcpu: The VCPU pointer
+ *
+ * Go over the list of "interesting" interrupts, and prune those that we
+ * won't have to consider in the near future.
+ */
+static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+ struct vgic_irq *irq, *tmp;
+
+retry:
+ spin_lock(&vgic_cpu->ap_list_lock);
+
+ list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
+ struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
+
+ spin_lock(&irq->irq_lock);
+
+ BUG_ON(vcpu != irq->vcpu);
+
+ target_vcpu = vgic_target_oracle(irq);
+
+ if (!target_vcpu) {
+ /*
+ * We don't need to process this interrupt any
+ * further, move it off the list.
+ */
+ list_del(&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] 60+ messages in thread
* [PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (7 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 08/45] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 " Andre Przywara
` (36 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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.
Also add vgic_v2_irq_change_affinity() to change the target VCPU of a
particular interrupt.
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
---
virt/kvm/arm/vgic/vgic-v2.c | 175 ++++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 19 +++--
virt/kvm/arm/vgic/vgic.h | 6 ++
3 files changed, 190 insertions(+), 10 deletions(-)
create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
new file mode 100644
index 0000000..43c19fb
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -0,0 +1,175 @@
+/*
+ * 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;
+ }
+
+ 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 65fa9ac..86c253d 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -385,10 +385,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. */
@@ -397,14 +399,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)
@@ -429,14 +435,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) {
@@ -454,14 +458,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] 60+ messages in thread
* [PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (8 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 11/45] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq Andre Przywara
` (35 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
From: Marc Zyngier <marc.zyngier@arm.com>
As the GICv3 virtual interface registers differ from their GICv2
siblings, we need different handlers for processing maintenance
interrupts and reading/writing to the LRs.
Also as we store an IRQ's affinity directly as a MPIDR, we need a
separate change_affinity() implementation too.
Implement the respective handler functions and connect them to
existing code to be called if the host is using a GICv3.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Changelog RFC..v1:
- remove outdated comment about the dist_lock
- add WARN_ON about LR_STATE not being 0 in maintenance interrupts
---
virt/kvm/arm/vgic/vgic-v3.c | 167 ++++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 25 +++++--
virt/kvm/arm/vgic/vgic.h | 29 ++++++++
3 files changed, 216 insertions(+), 5 deletions(-)
create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
new file mode 100644
index 0000000..6343d8fd
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -0,0 +1,167 @@
+/*
+ * 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;
+
+ 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 86c253d..13280b0 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -385,12 +385,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. */
@@ -400,17 +406,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] 60+ messages in thread
* [PATCH 11/45] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (9 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 " Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework Andre Przywara
` (34 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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 97c919c..664004f 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 13280b0..b1dd8d1 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -507,3 +507,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] 60+ messages in thread
* [PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (10 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 11/45] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface Andre Przywara
` (33 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
We register a kvm_io_bus device for the distributor and dispatch
the calls to the actual register handler at runtime.
Ideally we would register each register group directly with the
kvm_io_bus framework, but currently we run into the limit of 1000
devices pretty quickly (with GICv3), so we use this approach here, at
least for the time being.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
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)
---
include/kvm/vgic/vgic.h | 9 ++
virt/kvm/arm/vgic/vgic_mmio.c | 226 ++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic_mmio.h | 53 ++++++++++
3 files changed, 288 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 664004f..f331469 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -106,6 +106,12 @@ struct vgic_irq {
enum vgic_irq_config config; /* Level or edge */
};
+struct vgic_io_device {
+ gpa_t base_addr;
+ struct kvm_vcpu *redist_vcpu;
+ struct kvm_io_device dev;
+};
+
struct vgic_dist {
bool in_kernel;
bool ready;
@@ -132,6 +138,9 @@ struct vgic_dist {
u32 enabled;
struct vgic_irq *spis;
+
+ struct vgic_io_device dist_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..b70a274
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -0,0 +1,226 @@
+/*
+ * VGIC MMIO handling functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/iodev.h>
+#include <kvm/vgic/vgic.h>
+#include <linux/bitops.h>
+#include <linux/irqchip/arm-gic.h>
+
+#include "vgic.h"
+#include "vgic_mmio.h"
+
+void write_mask32(u32 value, int offset, int len, void *val)
+{
+ value = cpu_to_le32(value) >> (offset * 8);
+ memcpy(val, &value, len);
+}
+
+u32 mask32(u32 origvalue, int offset, int len, const void *val)
+{
+ origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
+ memcpy((char *)&origvalue + (offset * 8), val, len);
+ return origvalue;
+}
+
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void write_mask64(u64 value, int offset, int len, void *val)
+{
+ value = cpu_to_le64(value) >> (offset * 8);
+ memcpy(val, &value, len);
+}
+
+/* FIXME: I am clearly misguided here, there must be some saner way ... */
+u64 mask64(u64 origvalue, int offset, int len, const void *val)
+{
+ origvalue &= ~((BIT_ULL(len) - 1) << (offset * 8));
+ memcpy((char *)&origvalue + (offset * 8), val, len);
+ return origvalue;
+}
+#endif
+
+int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ memset(val, 0, len);
+
+ return 0;
+}
+
+int vgic_mmio_read_rao(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ memset(val, 0xff, len);
+
+ return 0;
+}
+
+int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ return 0;
+}
+
+static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
+ vcpu->vcpu_id, (unsigned long long)addr);
+ return 0;
+}
+
+static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
+ vcpu->vcpu_id, (unsigned long long)addr);
+ return 0;
+}
+
+struct vgic_register_region vgic_v2_dist_registers[] = {
+ REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
+ vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+ REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+ REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
+ REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+ REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+};
+
+/* Find the proper register handler entry given a certain address offset. */
+static struct vgic_register_region *
+vgic_find_mmio_region(struct vgic_register_region *region, int nr_regions,
+ int offset)
+{
+ int i;
+
+ for (i = 0; i < nr_regions; i++) {
+ int reg_size = region[i].len;
+
+ if (!reg_size)
+ reg_size = (region[i].bits_per_irq * 1024) / 8;
+
+ if ((offset < region[i].reg_offset) ||
+ (offset >= region[i].reg_offset + reg_size))
+ continue;
+
+ return region + i;
+ }
+
+ return NULL;
+}
+
+static int dispatch_mmio_read(struct kvm_vcpu *vcpu,
+ struct vgic_register_region *regions,
+ int nr_regions, struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ struct vgic_register_region *region;
+
+ region = vgic_find_mmio_region(regions, nr_regions,
+ addr - iodev->base_addr);
+ if (!region)
+ return -EOPNOTSUPP;
+
+ return region->ops.read(vcpu, dev, addr, len, val);
+}
+
+static int dispatch_mmio_write(struct kvm_vcpu *vcpu,
+ struct vgic_register_region *regions,
+ int nr_regions, struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ struct vgic_register_region *region;
+
+ region = vgic_find_mmio_region(regions, nr_regions,
+ addr - iodev->base_addr);
+ if (!region)
+ return -EOPNOTSUPP;
+
+ return region->ops.write(vcpu, dev, addr, len, val);
+}
+
+int vgic_mmio_read_v2dist(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ return dispatch_mmio_read(vcpu, vgic_v2_dist_registers,
+ ARRAY_SIZE(vgic_v2_dist_registers), dev,
+ addr, len, val);
+}
+
+int vgic_mmio_write_v2dist(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ return dispatch_mmio_write(vcpu, vgic_v2_dist_registers,
+ ARRAY_SIZE(vgic_v2_dist_registers), dev,
+ addr, len, val);
+}
+
+struct kvm_io_device_ops kvm_io_v2dist_ops = {
+ .read = vgic_mmio_read_v2dist,
+ .write = vgic_mmio_write_v2dist,
+};
+
+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;
+ int len;
+
+ switch (type) {
+ case VGIC_V2:
+ kvm_iodevice_init(&io_device->dev, &kvm_io_v2dist_ops);
+ len = SZ_4K;
+ break;
+ default:
+ BUG_ON(1);
+ }
+
+ io_device->base_addr = dist_base_address;
+
+ 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
new file mode 100644
index 0000000..9b17e1b
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_mmio.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __KVM_ARM_VGIC_MMIO_H__
+#define __KVM_ARM_VGIC_MMIO_H__
+
+struct vgic_register_region {
+ int reg_offset;
+ int len;
+ int bits_per_irq;
+ struct kvm_io_device_ops ops;
+};
+
+/*
+ * 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(name, read_ops, write_ops, bpi) \
+ {.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
+ .ops.read = read_ops, .ops.write = write_ops}
+#define REGISTER_DESC_WITH_LENGTH(name, read_ops, write_ops, length) \
+ {.reg_offset = name, .bits_per_irq = 0, .len = length, \
+ .ops.read = read_ops, .ops.write = write_ops}
+
+int vgic_mmio_read_raz(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+ gpa_t addr, int len, void *val);
+int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+ gpa_t addr, int len, const void *val);
+int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
+ struct vgic_register_region *reg_desc,
+ struct vgic_io_device *region,
+ int nr_irqs, bool offset_private);
+
+void write_mask32(u32 value, int offset, int len, void *val);
+void write_mask64(u64 value, int offset, int len, void *val);
+u32 mask32(u32 origvalue, int offset, int len, const void *val);
+u64 mask64(u64 origvalue, int offset, int len, const void *val);
+
+#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (11 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers Andre Przywara
` (32 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Userland can access the emulated GIC to save and restore its state
for initialization or migration purposes.
The kvm_io_bus API requires an absolute gpa, which does not fit the
KVM_DEV_ARM_VGIC_GRP_DIST_REGS user API, that only provides relative
offsets. So we explicitly iterate our register list to connect
userland to the VGIC.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
virt/kvm/arm/vgic/vgic.h | 2 ++
virt/kvm/arm/vgic/vgic_mmio.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 0c92cda..8f5d50a 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_access(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, int len, void *val);
#ifdef CONFIG_KVM_ARM_VGIC_V3
void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index b70a274..21c78a7 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -178,6 +178,36 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu,
return region->ops.write(vcpu, dev, addr, len, val);
}
+/*
+ * 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.
+ */
+static int vgic_device_mmio_access(struct kvm_vcpu *vcpu,
+ struct vgic_register_region *regions,
+ int nr_regions, bool is_write,
+ int offset, int len, void *val)
+{
+ struct vgic_io_device dev = {
+ .base_addr = 0,
+ .redist_vcpu = vcpu,
+ };
+
+ if (is_write)
+ return dispatch_mmio_write(vcpu, regions, nr_regions,
+ &dev.dev, offset, len, val);
+ else
+ return dispatch_mmio_read(vcpu, regions, nr_regions,
+ &dev.dev, offset, len, val);
+}
+
+int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, int len, void *val)
+{
+ return vgic_device_mmio_access(vcpu, vgic_v2_dist_registers,
+ ARRAY_SIZE(vgic_v2_dist_registers),
+ is_write, offset, len, val);
+}
+
int vgic_mmio_read_v2dist(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
gpa_t addr, int len, void *val)
{
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (12 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 15/45] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers Andre Przywara
` (31 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Changelog RFC..v1:
- kick VCPUs is the distributor gets enabled
- improve comment
---
virt/kvm/arm/vgic/vgic.h | 3 +++
virt/kvm/arm/vgic/vgic_mmio.c | 50 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 8f5d50a..59fddbf 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,
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 21c78a7..8ef1902 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -90,9 +90,57 @@ static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
return 0;
}
+static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ u32 value;
+
+ switch (addr & 0x0c) {
+ case 0x0:
+ value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
+ break;
+ case 0x4:
+ value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+ value = (value >> 5) - 1;
+ value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
+ break;
+ case 0x8:
+ value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+ break;
+ default:
+ return 0;
+ }
+
+ write_mask32(value, addr & 3, len, val);
+ return 0;
+}
+
+static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ bool was_enabled = dist->enabled;
+
+ /*
+ * GICD_TYPER and GICD_IIDR are read-only, the upper three bytes of
+ * GICD_CTLR are reserved.
+ */
+ if ((addr & 0x0f) >= 1)
+ return 0;
+
+ vcpu->kvm->arch.vgic.enabled = (*(u32 *)val) ? true : false;
+
+ if (!was_enabled && dist->enabled)
+ vgic_kick_vcpus(vcpu->kvm);
+
+ return 0;
+}
+
struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 12),
+ vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 15/45] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (13 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING " Andre Przywara
` (30 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
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
---
virt/kvm/arm/vgic/vgic_mmio.c | 80 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 78 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 8ef1902..b9850eb 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -138,15 +138,91 @@ static int vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
return 0;
}
+/*
+ * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
+ * of the enabled bit, so there is only one function for both here.
+ */
+static int vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = (addr & 0x7f) * 8;
+ u32 value = 0;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ /* Loop over all IRQs affected by this read */
+ for (i = 0; i < len * 8; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ if (irq->enabled)
+ value |= (1U << i);
+ }
+
+ write_mask32(value, addr & 3, len, val);
+ return 0;
+}
+
+static int vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ for_each_set_bit(i, val, len * 8) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ spin_lock(&irq->irq_lock);
+ irq->enabled = true;
+ vgic_queue_irq_unlock(vcpu->kvm, irq);
+ }
+
+ return 0;
+}
+
+static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ for_each_set_bit(i, val, len * 8) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ spin_lock(&irq->irq_lock);
+
+ irq->enabled = false;
+
+ spin_unlock(&irq->irq_lock);
+ }
+ return 0;
+}
+
struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (14 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 15/45] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 17/45] KVM: arm/arm64: vgic-new: Add PRIORITY " Andre Przywara
` (29 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Changelog RFC..v1:
- remove IRQ lock from read handler
- remove TODO from clear pending handler
---
virt/kvm/arm/vgic/vgic_mmio.c | 84 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 82 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index b9850eb..7010b15 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -214,6 +214,86 @@ static int vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
return 0;
}
+static int vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = (addr & 0x7f) * 8;
+ u32 value = 0;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ /* Loop over all IRQs affected by this read */
+ for (i = 0; i < len * 8; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ if (irq->pending)
+ value |= (1U << i);
+ }
+
+ write_mask32(value, addr & 3, len, val);
+ return 0;
+}
+
+static int vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ for_each_set_bit(i, val, len * 8) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ spin_lock(&irq->irq_lock);
+ irq->pending = true;
+ if (irq->config == VGIC_CONFIG_LEVEL)
+ irq->soft_pending = true;
+
+ vgic_queue_irq_unlock(vcpu->kvm, irq);
+ }
+
+ return 0;
+}
+
+static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ for_each_set_bit(i, val, len * 8) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ spin_lock(&irq->irq_lock);
+
+ if (irq->config == VGIC_CONFIG_LEVEL) {
+ irq->soft_pending = false;
+ irq->pending = irq->line_level;
+ } else {
+ irq->pending = false;
+ }
+
+ spin_unlock(&irq->irq_lock);
+ }
+ return 0;
+}
+
struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -224,9 +304,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 17/45] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (15 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING " Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 18/45] KVM: arm/arm64: vgic-new: Add ACTIVE " Andre Przywara
` (28 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
virt/kvm/arm/vgic/vgic_mmio.c | 46 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 7010b15..8e1e051 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -294,6 +294,50 @@ static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
return 0;
}
+static int vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = addr & 0x3ff;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ for (i = 0; i < len; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ ((u8 *)val)[i] = irq->priority;
+ }
+
+ return 0;
+}
+
+static int vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = addr & 0x3ff;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ for (i = 0; i < len; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ spin_lock(&irq->irq_lock);
+ irq->priority = ((u8 *)val)[i];
+ spin_unlock(&irq->irq_lock);
+ }
+
+ return 0;
+}
+
struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -312,7 +356,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+ vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 18/45] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (16 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 17/45] KVM: arm/arm64: vgic-new: Add PRIORITY " Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 19/45] KVM: arm/arm64: vgic-new: Add CONFIG " Andre Przywara
` (27 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Changelog RFC..v1:
- handling queueing in write handler
- remove IRQ lock from read handler
---
virt/kvm/arm/vgic/vgic_mmio.c | 143 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 141 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 8e1e051..3c3dbce 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -294,6 +294,145 @@ static int vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
return 0;
}
+static int vgic_mmio_read_active(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = (addr & 0x7f) * 8;
+ u32 value = 0;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ /* Loop over all IRQs affected by this read */
+ for (i = 0; i < len * 8; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ if (irq->active)
+ value |= (1U << i);
+ }
+
+ write_mask32(value, addr & 3, len, val);
+ return 0;
+}
+
+static int vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ for_each_set_bit(i, val, len * 8) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ spin_lock(&irq->irq_lock);
+
+ irq->active = false;
+
+ /*
+ * 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);
+ }
+ return 0;
+}
+
+static int vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = (addr & 0x7f) * 8;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ for_each_set_bit(i, val, len * 8) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ spin_lock(&irq->irq_lock);
+
+ /* 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);
+ }
+ return 0;
+}
+
static int vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
struct kvm_io_device *dev,
gpa_t addr, int len, void *val)
@@ -352,9 +491,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 1),
+ vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 19/45] KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (17 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 18/45] KVM: arm/arm64: vgic-new: Add ACTIVE " Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET " Andre Przywara
` (26 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
virt/kvm/arm/vgic/vgic_mmio.c | 62 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 61 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 3c3dbce..a8a96c8 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -477,6 +477,66 @@ static int vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
return 0;
}
+static int vgic_mmio_read_config(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = (addr & 0xff) * 4;
+ u32 value = 0;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ for (i = 0; i < len * 4; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ if (irq->config == VGIC_CONFIG_EDGE)
+ value |= (2U << (i * 2));
+ }
+
+ write_mask32(value, addr & 3, len, val);
+ return 0;
+}
+
+static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ u32 intid = (addr & 0xff) * 4;
+ int i;
+
+ if (iodev->redist_vcpu)
+ vcpu = iodev->redist_vcpu;
+
+ for (i = 0; i < len * 4; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ if (intid + i < 16)
+ continue;
+
+ /*
+ * The spec says that interrupts must be disabled before
+ * changing the configuration to avoid UNDEFINED behaviour.
+ */
+
+ 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);
+ }
+
+ return 0;
+}
+
struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -499,7 +559,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+ vgic_mmio_read_config, vgic_mmio_write_config, 2),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (18 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 19/45] KVM: arm/arm64: vgic-new: Add CONFIG " Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 21/45] KVM: arm/arm64: vgic-new: Add SGIR register handler Andre Przywara
` (25 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
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()
---
virt/kvm/arm/vgic/vgic_mmio.c | 45 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 44 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index a8a96c8..b2f329a 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -537,6 +537,49 @@ static int vgic_mmio_write_config(struct kvm_vcpu *vcpu,
return 0;
}
+static int vgic_mmio_read_target(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *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);
+
+ ((u8 *)val)[i] = irq->targets;
+ }
+
+ return 0;
+}
+
+static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ u32 intid = addr & 0x3ff;
+ int i;
+
+ /* GICD_ITARGETSR[0-7] are read-only */
+ if (intid < VGIC_NR_PRIVATE_IRQS)
+ return 0;
+
+ 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 = ((u8 *)val)[i];
+ target = irq->targets ? __ffs(irq->targets) : 0;
+ irq->target_vcpu = kvm_get_vcpu(vcpu->kvm, target);
+
+ spin_unlock(&irq->irq_lock);
+ }
+
+ return 0;
+}
+
struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -557,7 +600,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 8),
+ vgic_mmio_read_target, vgic_mmio_write_target, 8),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
vgic_mmio_read_config, vgic_mmio_write_config, 2),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 21/45] KVM: arm/arm64: vgic-new: Add SGIR register handler
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (19 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET " Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 22/45] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers Andre Przywara
` (24 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Changelog RFC..v1:
- silently return on illegal TargetListFilter value (=3)
---
virt/kvm/arm/vgic/vgic_mmio.c | 46 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index b2f329a..83641b3 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -580,6 +580,50 @@ static int vgic_mmio_write_target(struct kvm_vcpu *vcpu,
return 0;
}
+static int vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ int nr_vcpus = atomic_read(&source_vcpu->kvm->online_vcpus);
+ u32 value = *(u32 *)val;
+ int intid = value & 0xf;
+ int targets = (value >> 16) & 0xff;
+ int mode = (value >> 24) & 0x03;
+ int c;
+ struct kvm_vcpu *vcpu;
+
+ switch (mode) {
+ case 0x0: /* as specified by targets */
+ break;
+ case 0x1:
+ targets = (1U << nr_vcpus) - 1; /* all, ... */
+ targets &= ~(1U << source_vcpu->vcpu_id); /* but self */
+ break;
+ case 0x2: /* this very vCPU only */
+ targets = (1U << source_vcpu->vcpu_id);
+ break;
+ case 0x3: /* reserved */
+ return 0;
+ }
+
+ 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);
+ }
+
+ return 0;
+}
+
struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -604,7 +648,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
vgic_mmio_read_config, vgic_mmio_write_config, 2),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 4),
+ vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 22/45] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (20 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 21/45] KVM: arm/arm64: vgic-new: Add SGIR register handler Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Andre Przywara
` (23 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
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
---
virt/kvm/arm/vgic/vgic_mmio.c | 64 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 62 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 83641b3..daa2e00 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -624,6 +624,66 @@ static int vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
return 0;
}
+static int vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *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);
+
+ ((u8 *)val)[i] = irq->source;
+ }
+ return 0;
+}
+
+static int vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *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 &= ~((u8 *)val)[i];
+ if (!irq->source)
+ irq->pending = false;
+
+ spin_unlock(&irq->irq_lock);
+ }
+ return 0;
+}
+
+static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *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 |= ((u8 *)val)[i];
+
+ if (irq->source) {
+ irq->pending = true;
+ vgic_queue_irq_unlock(vcpu->kvm, irq);
+ } else {
+ spin_unlock(&irq->irq_lock);
+ }
+ }
+ return 0;
+}
+
struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -650,9 +710,9 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+ vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16),
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
+ vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
};
/* Find the proper register handler entry given a certain address offset. */
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (21 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 22/45] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-26 10:14 ` Marc Zyngier
2016-04-15 17:11 ` [PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers Andre Przywara
` (22 subsequent siblings)
45 siblings, 1 reply; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Describe the GICv3 distributor and redistributor registers in our
structure. This adds a special macro to deal with the split of
SGI/PPI in the redistributor and SPIs in the distributor, which
allows us to reuse the existing GICv2 handlers for those registers
which are compatible.
Also we register the separate MMIO page for the redistributor
registers dealing with private interrupts.
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
---
virt/kvm/arm/vgic/vgic.h | 16 +++
virt/kvm/arm/vgic/vgic_mmio.c | 269 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 285 insertions(+)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 59fddbf..ccae13e 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -40,6 +40,10 @@ 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);
+int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, int len, void *val);
+int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, int len, void *val);
#else
static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
{
@@ -61,6 +65,18 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
{
}
+
+static inline int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, int len, void *val)
+{
+ return -ENXIO;
+}
+
+static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, int len, void *val)
+{
+ return -ENXIO;
+}
#endif
#endif
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index daa2e00..4a31d60 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -17,6 +17,8 @@
#include <kvm/vgic/vgic.h>
#include <linux/bitops.h>
#include <linux/irqchip/arm-gic.h>
+#include <linux/irqchip/arm-gic-v3.h>
+#include <asm/kvm_emulate.h>
#include "vgic.h"
#include "vgic_mmio.h"
@@ -684,6 +686,20 @@ static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
return 0;
}
+/*
+ * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
+ * redistributors, while SPIs are covered by registers in the distributor
+ * block. Trying to set private IRQs in this block gets ignored.
+ * We take some special care here to fix the calculation of the register
+ * offset.
+ */
+#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(name, read_ops, write_ops, bpi) \
+ {.reg_offset = name, .bits_per_irq = 0, \
+ .len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8, \
+ .ops.read = vgic_mmio_read_raz, .ops.write = vgic_mmio_write_wi, }, \
+ {.reg_offset = name, .bits_per_irq = bpi, .len = 0, \
+ .ops.read = read_ops, .ops.write = write_ops, }
+
struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -715,6 +731,79 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
};
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+struct vgic_register_region vgic_v3_dist_registers[] = {
+ REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
+ vgic_mmio_read_nyi, vgic_mmio_write_nyi, 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_nyi, vgic_mmio_write_nyi, 64),
+ REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
+ vgic_mmio_read_nyi, vgic_mmio_write_wi, 48),
+};
+
+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_nyi, vgic_mmio_write_wi, 4),
+ REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
+ vgic_mmio_read_nyi, 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_nyi, vgic_mmio_write_wi, 48),
+};
+
+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),
+};
+#endif
+
/* Find the proper register handler entry given a certain address offset. */
static struct vgic_register_region *
vgic_find_mmio_region(struct vgic_register_region *region, int nr_regions,
@@ -823,6 +912,121 @@ struct kvm_io_device_ops kvm_io_v2dist_ops = {
.write = vgic_mmio_write_v2dist,
};
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+int vgic_mmio_read_v3dist(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ struct vgic_register_region *region;
+ int offset = addr - iodev->base_addr;
+
+ region = vgic_find_mmio_region(vgic_v3_dist_registers,
+ ARRAY_SIZE(vgic_v3_dist_registers),
+ offset);
+ if (!region)
+ return 1;
+
+ /* Private IRQs are RAZ on the GICv3 distributor. */
+ if (region->bits_per_irq) {
+ offset -= region->reg_offset;
+ if ((offset * 8 / region->bits_per_irq) < VGIC_NR_PRIVATE_IRQS)
+ return vgic_mmio_read_raz(vcpu, dev, addr, len, val);
+ }
+
+ return region->ops.read(vcpu, dev, addr, len, val);
+}
+
+int vgic_mmio_write_v3dist(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ struct vgic_register_region *region;
+ int offset = addr - iodev->base_addr;
+
+ region = vgic_find_mmio_region(vgic_v3_dist_registers,
+ ARRAY_SIZE(vgic_v3_dist_registers),
+ offset);
+ if (!region)
+ return 1;
+
+ /* Private IRQs are WI on the GICv3 distributor. */
+ if (region->bits_per_irq) {
+ offset -= region->reg_offset;
+ if ((offset * 8 / region->bits_per_irq) < VGIC_NR_PRIVATE_IRQS)
+ return vgic_mmio_write_wi(vcpu, dev, addr, len, val);
+ }
+
+ return region->ops.write(vcpu, dev, addr, len, val);
+}
+
+struct kvm_io_device_ops kvm_io_v3dist_ops = {
+ .read = vgic_mmio_read_v3dist,
+ .write = vgic_mmio_write_v3dist,
+};
+
+int vgic_mmio_read_v3redist(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ return dispatch_mmio_read(vcpu, vgic_v3_redist_registers,
+ ARRAY_SIZE(vgic_v3_redist_registers), dev,
+ addr, len, val);
+}
+
+int vgic_mmio_write_v3redist(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ return dispatch_mmio_write(vcpu, vgic_v3_redist_registers,
+ ARRAY_SIZE(vgic_v3_redist_registers), dev,
+ addr, len, val);
+}
+
+struct kvm_io_device_ops kvm_io_v3redist_ops = {
+ .read = vgic_mmio_read_v3redist,
+ .write = vgic_mmio_write_v3redist,
+};
+
+int vgic_mmio_read_v3redist_private(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ return dispatch_mmio_read(vcpu, vgic_v3_private_registers,
+ ARRAY_SIZE(vgic_v3_private_registers), dev,
+ addr, len, val);
+}
+
+int vgic_mmio_write_v3redist_private(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ return dispatch_mmio_write(vcpu, vgic_v3_private_registers,
+ ARRAY_SIZE(vgic_v3_private_registers), dev,
+ addr, len, val);
+}
+
+struct kvm_io_device_ops kvm_io_v3redist_private_ops = {
+ .read = vgic_mmio_read_v3redist_private,
+ .write = vgic_mmio_write_v3redist_private,
+};
+
+int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, int len, void *val)
+{
+ return vgic_device_mmio_access(vcpu, vgic_v3_dist_registers,
+ ARRAY_SIZE(vgic_v3_dist_registers),
+ is_write, offset, len, val);
+}
+
+int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, int len, void *val)
+{
+ return vgic_device_mmio_access(vcpu, vgic_v3_redist_registers,
+ ARRAY_SIZE(vgic_v3_redist_registers),
+ is_write, offset, len, val);
+}
+#endif
+
int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
enum vgic_type type)
{
@@ -835,6 +1039,12 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
kvm_iodevice_init(&io_device->dev, &kvm_io_v2dist_ops);
len = SZ_4K;
break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+ case VGIC_V3:
+ kvm_iodevice_init(&io_device->dev, &kvm_io_v3dist_ops);
+ len = SZ_64K;
+ break;
+#endif
default:
BUG_ON(1);
}
@@ -848,3 +1058,62 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
return ret;
}
+
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+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 *regions, *region;
+ int c, ret = 0;
+
+ regions = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
+ GFP_KERNEL);
+ if (!regions)
+ return -ENOMEM;
+
+ region = regions;
+ kvm_for_each_vcpu(c, vcpu, kvm) {
+ kvm_iodevice_init(®ion->dev, &kvm_io_v3redist_ops);
+ region->base_addr = redist_base_address;
+
+ mutex_lock(&kvm->slots_lock);
+ ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+ redist_base_address,
+ SZ_64K, ®ion->dev);
+ mutex_unlock(&kvm->slots_lock);
+
+ if (ret)
+ break;
+
+ region++;
+ kvm_iodevice_init(®ion->dev, &kvm_io_v3redist_private_ops);
+ region->base_addr = redist_base_address + SZ_64K;
+
+ mutex_lock(&kvm->slots_lock);
+ ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+ redist_base_address + SZ_64K,
+ SZ_64K, ®ion->dev);
+ mutex_unlock(&kvm->slots_lock);
+ if (ret) {
+ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+ ®ions[c * 2].dev);
+ break;
+ }
+ redist_base_address += 2 * SZ_64K;
+ }
+
+ if (ret) {
+ for (c--; c >= 0; c--) {
+ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+ ®ions[c * 2].dev);
+ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+ ®ions[c * 2 + 1].dev);
+ }
+ } else {
+ kvm->arch.vgic.redist_iodevs = regions;
+ }
+
+ return ret;
+}
+#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (22 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-19 12:26 ` Peter Maydell
2016-04-15 17:11 ` [PATCH 25/45] KVM: arm/arm64: vgic-new: Add GICv3 redistributor " Andre Przywara
` (21 subsequent siblings)
45 siblings, 1 reply; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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
---
virt/kvm/arm/vgic/vgic.h | 2 ++
virt/kvm/arm/vgic/vgic_mmio.c | 56 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index ccae13e..83b342c 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,
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 4a31d60..a87bbca 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -686,6 +686,60 @@ static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
return 0;
}
+/*****************************/
+/* GICv3 emulation functions */
+/*****************************/
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+
+static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ 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;
+ }
+
+ write_mask32(value, addr & 3, len, val);
+ return 0;
+}
+
+static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ bool was_enabled = dist->enabled;
+
+ /* Of the whole region only the first byte is actually writeable. */
+ if ((addr & 0x0f) > 0)
+ return 0;
+
+ /* We only care about the enable bit, all other bits are WI. */
+ dist->enabled = *(u8*)val & GICD_CTLR_ENABLE_SS_G1;
+
+ if (!was_enabled && dist->enabled)
+ vgic_kick_vcpus(vcpu->kvm);
+
+ return 0;
+}
+
+
/*
* The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
* redistributors, while SPIs are covered by registers in the distributor
@@ -734,7 +788,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
#ifdef CONFIG_KVM_ARM_VGIC_V3
struct vgic_register_region vgic_v3_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
- vgic_mmio_read_nyi, vgic_mmio_write_nyi, 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,
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 25/45] KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR, TYPER handlers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (23 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler Andre Przywara
` (20 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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>
---
virt/kvm/arm/vgic/vgic_mmio.c | 50 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 48 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index a87bbca..7d275a7 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -739,6 +739,52 @@ static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
return 0;
}
+/*
+ * We use a compressed version of the MPIDR (all 32 bits in one 32-bit word)
+ * when we store the target MPIDR written by the guest.
+ */
+static u32 compress_mpidr(unsigned long mpidr)
+{
+ u32 ret;
+
+ ret = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ ret |= MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8;
+ ret |= MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16;
+ ret |= MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24;
+
+ return ret;
+}
+
+static int vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ struct vgic_io_device *iodev = container_of(dev,
+ struct vgic_io_device, dev);
+ unsigned long mpidr = kvm_vcpu_get_mpidr_aff(iodev->redist_vcpu);
+ int target_vcpu_id = iodev->redist_vcpu->vcpu_id;
+ u64 value;
+
+ value = (u64)compress_mpidr(mpidr) << 32;
+ value |= ((target_vcpu_id & 0xffff) << 8);
+ if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
+ value |= GICR_TYPER_LAST;
+
+ write_mask64(value, addr & 7, len, val);
+ return 0;
+}
+
+static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ write_mask32((PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0),
+ addr & 3, len, val);
+
+ return 0;
+}
+
+#endif
/*
* The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
@@ -821,9 +867,9 @@ 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_nyi, vgic_mmio_write_wi, 4),
+ vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
- vgic_mmio_read_nyi, 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] 60+ messages in thread
* [PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (24 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 25/45] KVM: arm/arm64: vgic-new: Add GICv3 redistributor " Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-19 12:34 ` Peter Maydell
2016-04-15 17:11 ` [PATCH 27/45] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers Andre Przywara
` (19 subsequent siblings)
45 siblings, 1 reply; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
virt/kvm/arm/vgic/vgic_mmio.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 7d275a7..dafa235 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -784,6 +784,23 @@ static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
return 0;
}
+static int vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ 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;
+ }
+
+ write_mask32(reg , addr & 3, len, val);
+ return 0;
+}
#endif
/*
@@ -860,7 +877,7 @@ struct vgic_register_region vgic_v3_dist_registers[] = {
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
vgic_mmio_read_nyi, vgic_mmio_write_nyi, 64),
REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
- vgic_mmio_read_nyi, vgic_mmio_write_wi, 48),
+ vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
};
struct vgic_register_region vgic_v3_redist_registers[] = {
@@ -875,7 +892,7 @@ 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_nyi, vgic_mmio_write_wi, 48),
+ vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
};
struct vgic_register_region vgic_v3_private_registers[] = {
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 27/45] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (25 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler Andre Przywara
` (18 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Those set the affinity of a SPI interrupt.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Changelog RFC..v1:
- fold in and simplify vgic_v3_irq_change_affinity
---
virt/kvm/arm/vgic/vgic_mmio.c | 73 ++++++++++++++++++++++++++++++++-----------
1 file changed, 54 insertions(+), 19 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index dafa235..3f03101 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -74,24 +74,6 @@ int vgic_mmio_write_wi(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
return 0;
}
-static int vgic_mmio_read_nyi(struct kvm_vcpu *vcpu,
- struct kvm_io_device *dev,
- gpa_t addr, int len, void *val)
-{
- pr_warn("KVM: handling unimplemented VGIC MMIO read: VCPU %d, address: 0x%llx\n",
- vcpu->vcpu_id, (unsigned long long)addr);
- return 0;
-}
-
-static int vgic_mmio_write_nyi(struct kvm_vcpu *vcpu,
- struct kvm_io_device *dev,
- gpa_t addr, int len, const void *val)
-{
- pr_warn("KVM: handling unimplemented VGIC MMIO write: VCPU %d, address: 0x%llx\n",
- vcpu->vcpu_id, (unsigned long long)addr);
- return 0;
-}
-
static int vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
struct kvm_io_device *dev,
gpa_t addr, int len, void *val)
@@ -755,6 +737,59 @@ static u32 compress_mpidr(unsigned long mpidr)
return ret;
}
+static unsigned long decompress_mpidr(u32 value)
+{
+ unsigned long mpidr;
+
+ mpidr = ((value >> 0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
+ mpidr |= ((value >> 8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
+ mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
+ mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
+
+ return mpidr;
+}
+
+static int vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ int intid = (addr & 0x1fff) / 8;
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+
+ if (!irq) {
+ memset(val, 0, len);
+ return 0;
+ }
+
+ write_mask64(decompress_mpidr(irq->mpidr), addr & 7, len, val);
+
+ return 0;
+}
+
+static int vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
+ struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ int intid = (addr & 0x1fff) / 8;
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+ u64 mpidr;
+
+ if (!irq)
+ return 0;
+
+ mpidr = decompress_mpidr(irq->mpidr);
+ mpidr = mask64(mpidr, addr & 7, len, val);
+
+ spin_lock(&irq->irq_lock);
+
+ irq->mpidr = compress_mpidr(mpidr);
+ irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
+
+ spin_unlock(&irq->irq_lock);
+
+ return 0;
+}
+
static int vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
struct kvm_io_device *dev,
gpa_t addr, int len, void *val)
@@ -875,7 +910,7 @@ 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_nyi, vgic_mmio_write_nyi, 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] 60+ messages in thread
* [PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (26 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 27/45] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-19 12:40 ` Peter Maydell
2016-04-15 17:11 ` [PATCH 29/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration Andre Przywara
` (17 subsequent siblings)
45 siblings, 1 reply; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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.c | 106 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 114 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index f331469..6139e11 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -205,6 +205,14 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
+#else
+static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
+{
+}
+#endif
+
/**
* kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
*
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index 3f03101..fd95f3d 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -1268,4 +1268,110 @@ 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);
+ }
+}
#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 29/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (27 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 30/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS Andre Przywara
` (16 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
From: Eric Auger <eric.auger@linaro.org>
This patch introduces the skeleton for the KVM device operations
associated to KVM_DEV_TYPE_ARM_VGIC_V2 and KVM_DEV_TYPE_ARM_VGIC_V3.
At that stage kvm_vgic_create is stubbed.
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
virt/kvm/arm/vgic/vgic.h | 2 +
virt/kvm/arm/vgic/vgic_kvm_device.c | 108 ++++++++++++++++++++++++++++++++++++
2 files changed, 110 insertions(+)
create mode 100644 virt/kvm/arm/vgic/vgic_kvm_device.c
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 83b342c..e1543a7 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -81,4 +81,6 @@ static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
}
#endif
+void kvm_register_vgic_device(unsigned long type);
+
#endif
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
new file mode 100644
index 0000000..7c665f9
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -0,0 +1,108 @@
+/*
+ * VGIC: KVM DEVICE API
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kvm_host.h>
+#include <kvm/vgic/vgic.h>
+
+/* common helpers */
+
+static int vgic_create(struct kvm_device *dev, u32 type)
+{
+ return kvm_vgic_create(dev->kvm, type);
+}
+
+static void vgic_destroy(struct kvm_device *dev)
+{
+ kfree(dev);
+}
+
+void kvm_register_vgic_device(unsigned long type)
+{
+ switch (type) {
+ case KVM_DEV_TYPE_ARM_VGIC_V2:
+ kvm_register_device_ops(&kvm_arm_vgic_v2_ops,
+ KVM_DEV_TYPE_ARM_VGIC_V2);
+ break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+ case KVM_DEV_TYPE_ARM_VGIC_V3:
+ kvm_register_device_ops(&kvm_arm_vgic_v3_ops,
+ KVM_DEV_TYPE_ARM_VGIC_V3);
+ break;
+#endif
+ }
+}
+
+/* V2 ops */
+
+static int vgic_v2_set_attr(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ return -ENXIO;
+}
+
+static int vgic_v2_get_attr(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ return -ENXIO;
+}
+
+static int vgic_v2_has_attr(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v2_ops = {
+ .name = "kvm-arm-vgic-v2",
+ .create = vgic_create,
+ .destroy = vgic_destroy,
+ .set_attr = vgic_v2_set_attr,
+ .get_attr = vgic_v2_get_attr,
+ .has_attr = vgic_v2_has_attr,
+};
+
+/* V3 ops */
+
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+
+static int vgic_v3_set_attr(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ return -ENXIO;
+}
+
+static int vgic_v3_get_attr(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ return -ENXIO;
+}
+
+static int vgic_v3_has_attr(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v3_ops = {
+ .name = "kvm-arm-vgic-v3",
+ .create = vgic_create,
+ .destroy = vgic_destroy,
+ .set_attr = vgic_v3_set_attr,
+ .get_attr = vgic_v3_get_attr,
+ .has_attr = vgic_v3_has_attr,
+};
+
+#endif /* CONFIG_KVM_ARM_VGIC_V3 */
+
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 30/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (28 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 29/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 31/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL Andre Przywara
` (15 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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] 60+ messages in thread
* [PATCH 31/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (29 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 30/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 32/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR Andre Przywara
` (14 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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] 60+ messages in thread
* [PATCH 32/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (30 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 31/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 33/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers Andre Przywara
` (13 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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] 60+ messages in thread
* [PATCH 33/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (31 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 32/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 34/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr Andre Przywara
` (12 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
From: Eric Auger <eric.auger@linaro.org>
This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
access VGIC registers.
At that stage the interfaces with the MMIO API are not implemented:
- vgic_attr_regs_access
- vgic_v2_has_attr_regs
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
virt/kvm/arm/vgic/vgic.h | 1 +
virt/kvm/arm/vgic/vgic_kvm_device.c | 53 +++++++++++++++++++++++++++++++++++--
virt/kvm/arm/vgic/vgic_mmio.c | 34 ++++++++++++++++++++++++
3 files changed, 86 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index e1543a7..e9fbcc90 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_access(struct kvm_vcpu *vcpu, bool is_write,
int offset, int len, void *val);
+int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
#ifdef CONFIG_KVM_ARM_VGIC_V3
void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index 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.c b/virt/kvm/arm/vgic/vgic_mmio.c
index fd95f3d..ec96188 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -1375,3 +1375,37 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
}
}
#endif
+
+int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+ int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+ struct vgic_register_region *regions;
+ gpa_t addr;
+ int nr_regions, i, len;
+
+ addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+ switch (attr->group) {
+ case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+ regions = vgic_v2_dist_registers;
+ nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+ break;
+ case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+ return -ENXIO; /* TODO: describe CPU i/f regs also */
+ default:
+ return -ENXIO;
+ }
+
+ for (i = 0; i < nr_regions; i++) {
+ if (regions[i].bits_per_irq)
+ len = (regions[i].bits_per_irq * nr_irqs) / 8;
+ else
+ len = regions[i].len;
+
+ if (regions[i].reg_offset <= addr &&
+ regions[i].reg_offset + len > addr)
+ return 0;
+ }
+
+ return -ENXIO;
+}
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 34/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (32 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 33/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 35/45] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers Andre Przywara
` (11 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
From: Eric Auger <eric.auger@linaro.org>
kvm_vgic_addr is used by the userspace to set the base address of
the following register regions, as seen by the guest:
- distributor(v2 and v3),
- re-distributors (v3),
- CPU interface (v2).
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
include/kvm/vgic/vgic.h | 2 +
virt/kvm/arm/vgic/vgic.h | 3 +
virt/kvm/arm/vgic/vgic_kvm_device.c | 112 ++++++++++++++++++++++++++++++++++++
3 files changed, 117 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 6139e11..e536d1d 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -190,6 +190,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.h b/virt/kvm/arm/vgic/vgic.h
index e9fbcc90..6ca69d3 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)
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index dfe40a0..d9f2383 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -16,10 +16,122 @@
#include <linux/kvm_host.h>
#include <kvm/vgic/vgic.h>
#include <linux/uaccess.h>
+#include <asm/kvm_mmu.h>
#include "vgic.h"
/* common helpers */
+static int vgic_ioaddr_overlap(struct kvm *kvm)
+{
+ phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
+ phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
+
+ if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
+ return 0;
+ if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
+ (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
+ return -EBUSY;
+ return 0;
+}
+
+static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
+ phys_addr_t addr, phys_addr_t size)
+{
+ int ret;
+
+ if (addr & ~KVM_PHYS_MASK)
+ return -E2BIG;
+
+ if (addr & (SZ_4K - 1))
+ return -EINVAL;
+
+ if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
+ return -EEXIST;
+ if (addr + size < addr)
+ return -EINVAL;
+
+ *ioaddr = addr;
+ ret = vgic_ioaddr_overlap(kvm);
+ if (ret)
+ *ioaddr = VGIC_ADDR_UNDEF;
+
+ return ret;
+}
+
+/**
+ * kvm_vgic_addr - set or get vgic VM base addresses
+ * @kvm: pointer to the vm struct
+ * @type: the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX
+ * @addr: pointer to address value
+ * @write: if true set the address in the VM address space, if false read the
+ * address
+ *
+ * Set or get the vgic base addresses for the distributor and the virtual CPU
+ * interface in the VM physical address space. These addresses are properties
+ * of the emulated core/SoC and therefore user space initially knows this
+ * information.
+ */
+int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
+{
+ int r = 0;
+ struct vgic_dist *vgic = &kvm->arch.vgic;
+ int type_needed;
+ phys_addr_t *addr_ptr, block_size;
+ phys_addr_t alignment;
+
+ mutex_lock(&kvm->lock);
+ switch (type) {
+ case KVM_VGIC_V2_ADDR_TYPE_DIST:
+ type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
+ addr_ptr = &vgic->vgic_dist_base;
+ block_size = KVM_VGIC_V2_DIST_SIZE;
+ alignment = SZ_4K;
+ break;
+ case KVM_VGIC_V2_ADDR_TYPE_CPU:
+ type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
+ addr_ptr = &vgic->vgic_cpu_base;
+ block_size = KVM_VGIC_V2_CPU_SIZE;
+ alignment = SZ_4K;
+ break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+ case KVM_VGIC_V3_ADDR_TYPE_DIST:
+ type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
+ addr_ptr = &vgic->vgic_dist_base;
+ block_size = KVM_VGIC_V3_DIST_SIZE;
+ alignment = SZ_64K;
+ break;
+ case KVM_VGIC_V3_ADDR_TYPE_REDIST:
+ type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
+ addr_ptr = &vgic->vgic_redist_base;
+ block_size = KVM_VGIC_V3_REDIST_SIZE;
+ alignment = SZ_64K;
+ break;
+#endif
+ default:
+ r = -ENODEV;
+ goto out;
+ }
+
+ if (vgic->vgic_model != type_needed) {
+ r = -ENODEV;
+ goto out;
+ }
+
+ if (write) {
+ if (!IS_ALIGNED(*addr, alignment))
+ r = -EINVAL;
+ else
+ r = vgic_ioaddr_assign(kvm, addr_ptr,
+ *addr, block_size);
+ } else {
+ *addr = *addr_ptr;
+ }
+
+out:
+ mutex_unlock(&kvm->lock);
+ return r;
+}
+
static int vgic_set_common_attr(struct kvm_device *dev,
struct kvm_device_attr *attr)
{
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 35/45] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (33 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 34/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 36/45] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors Andre Przywara
` (10 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
virt/kvm/arm/vgic/vgic_kvm_device.c | 50 ++++++++++++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index d9f2383..2e2f8b6 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -264,7 +264,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
struct kvm_device_attr *attr,
u32 *reg, bool is_write)
{
- return -ENXIO;
+ gpa_t addr;
+ int cpuid, ret, c;
+ struct kvm_vcpu *vcpu, *tmp_vcpu;
+
+ cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
+ KVM_DEV_ARM_VGIC_CPUID_SHIFT;
+ vcpu = kvm_get_vcpu(dev->kvm, cpuid);
+ addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+ mutex_lock(&dev->kvm->lock);
+
+ ret = vgic_init(dev->kvm);
+ if (ret)
+ goto out;
+
+ if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Ensure that no other VCPU is running by checking the vcpu->cpu
+ * field. If no other VPCUs are running we can safely access the VGIC
+ * state, because even if another VPU is run after this point, that
+ * VCPU will not touch the vgic state, because it will block on
+ * getting the vgic->lock in kvm_vgic_sync_hwstate().
+ */
+ kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) {
+ if (unlikely(tmp_vcpu->cpu != -1)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+
+ switch (attr->group) {
+ case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+ ret = -EINVAL;
+ break;
+ case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+ ret = vgic_v2_dist_access(vcpu, is_write, addr, 4, reg);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+out:
+ mutex_unlock(&dev->kvm->lock);
+ return ret;
}
/* V2 ops */
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 36/45] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (34 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 35/45] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 37/45] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access Andre Przywara
` (9 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
include/kvm/vgic/vgic.h | 7 +++++++
virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v3.c | 22 ++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.c | 16 ++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 18 ++++++++++++++++++
5 files changed, 92 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index e536d1d..910721a2 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -167,6 +167,13 @@ struct vgic_v3_cpu_if {
#endif
};
+struct vgic_vmcr {
+ u32 ctlr;
+ u32 abpr;
+ u32 bpr;
+ u32 pmr;
+};
+
struct vgic_cpu {
/* CPU vif control registers for world switch */
union {
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 43c19fb..904f142 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -173,3 +173,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 6343d8fd..7ba5110 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -165,3 +165,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 b1dd8d1..2110d95 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -428,6 +428,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 6ca69d3..ba4866f 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_access(struct kvm_vcpu *vcpu, bool is_write,
int offset, int len, void *val);
int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
+void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
#ifdef CONFIG_KVM_ARM_VGIC_V3
void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
@@ -50,6 +52,8 @@ int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
int offset, int len, void *val);
int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
int offset, int len, void *val);
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
#else
static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
{
@@ -83,8 +87,22 @@ static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
{
return -ENXIO;
}
+
+static inline
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+}
+
+static inline
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+}
+
#endif
+void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+
void kvm_register_vgic_device(unsigned long type);
#endif
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 37/45] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (35 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 36/45] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 38/45] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init Andre Przywara
` (8 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
virt/kvm/arm/vgic/vgic_kvm_device.c | 72 ++++++++++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index 2e2f8b6..7f78a16 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c
@@ -17,8 +17,11 @@
#include <kvm/vgic/vgic.h>
#include <linux/uaccess.h>
#include <asm/kvm_mmu.h>
+#include <linux/irqchip/arm-gic.h>
#include "vgic.h"
+#define GICC_ARCH_VERSION_V2 0x2
+
/* common helpers */
static int vgic_ioaddr_overlap(struct kvm *kvm)
@@ -252,6 +255,69 @@ void kvm_register_vgic_device(unsigned long type)
}
}
+static u32 vgic_read_vcpuif(struct kvm_vcpu *vcpu, int offset)
+{
+ struct vgic_vmcr vmcr;
+ u32 *field;
+
+ switch (offset) {
+ case GIC_CPU_CTRL:
+ field = &vmcr.ctlr;
+ break;
+ case GIC_CPU_PRIMASK:
+ field = &vmcr.pmr;
+ break;
+ case GIC_CPU_BINPOINT:
+ field = &vmcr.bpr;
+ break;
+ case GIC_CPU_ALIAS_BINPOINT:
+ field = &vmcr.abpr;
+ break;
+ case GIC_CPU_IDENT:
+ return (PRODUCT_ID_KVM << 20) |
+ (GICC_ARCH_VERSION_V2 << 16) |
+ (IMPLEMENTER_ARM << 0);
+ default:
+ return 0;
+ }
+
+ vgic_get_vmcr(vcpu, &vmcr);
+
+ return *field;
+}
+
+static bool vgic_write_vcpuif(struct kvm_vcpu *vcpu, int offset, u32 value)
+{
+ struct vgic_vmcr vmcr;
+ u32 *field;
+
+ switch (offset) {
+ case GIC_CPU_CTRL:
+ field = &vmcr.ctlr;
+ break;
+ case GIC_CPU_PRIMASK:
+ field = &vmcr.pmr;
+ break;
+ case GIC_CPU_BINPOINT:
+ field = &vmcr.bpr;
+ break;
+ case GIC_CPU_ALIAS_BINPOINT:
+ field = &vmcr.abpr;
+ break;
+ default:
+ return false;
+ }
+
+ vgic_get_vmcr(vcpu, &vmcr);
+ if (*field == value)
+ return false;
+
+ *field = value;
+ vgic_set_vmcr(vcpu, &vmcr);
+
+ return true;
+}
+
/** vgic_attr_regs_access: allows user space to read/write VGIC registers
*
* @dev: kvm device handle
@@ -300,7 +366,11 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
switch (attr->group) {
case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
- ret = -EINVAL;
+ ret = 0;
+ if (is_write)
+ vgic_write_vcpuif(vcpu, addr, *reg);
+ else
+ *reg = vgic_read_vcpuif(vcpu, addr);
break;
case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
ret = vgic_v2_dist_access(vcpu, is_write, addr, 4, reg);
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 38/45] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (36 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 37/45] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 39/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create Andre Przywara
` (7 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
From: Eric Auger <eric.auger@linaro.org>
Implements kvm_vgic_hyp_init and vgic_probe function.
The vgic_global struct is enriched with new fields populated
by those functions.
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
include/kvm/vgic/vgic.h | 1 +
virt/kvm/arm/vgic/vgic-v2.c | 90 +++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v3.c | 74 +++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 6 +++
virt/kvm/arm/vgic/vgic_init.c | 122 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 293 insertions(+)
create mode 100644 virt/kvm/arm/vgic/vgic_init.c
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 910721a2..e16bfeb 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -198,6 +198,7 @@ struct vgic_cpu {
};
int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+int kvm_vgic_hyp_init(void);
int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
bool level);
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 904f142..3c3d3a0 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"
@@ -202,3 +207,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 7ba5110..6e93d8f 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;
@@ -187,3 +195,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 ba4866f..0f55d21 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -41,6 +41,7 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+int vgic_v2_probe(struct device_node *vgic_node);
#ifdef CONFIG_KVM_ARM_VGIC_V3
void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
@@ -54,6 +55,7 @@ int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
int offset, int len, void *val);
void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+int vgic_v3_probe(struct device_node *vgic_node);
#else
static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
{
@@ -98,6 +100,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
{
}
+static inline int vgic_v3_probe(struct device_node *vgic_node)
+{
+ return -ENODEV;
+}
#endif
void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
new file mode 100644
index 0000000..d7c50bb
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_init.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/cpu.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/kvm_host.h>
+#include <kvm/vgic/vgic.h>
+#include <asm/kvm_mmu.h>
+#include "vgic.h"
+
+/* GENERIC PROBE */
+
+static void vgic_init_maintenance_interrupt(void *info)
+{
+ enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0);
+}
+
+static int vgic_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *cpu)
+{
+ switch (action) {
+ case CPU_STARTING:
+ case CPU_STARTING_FROZEN:
+ vgic_init_maintenance_interrupt(NULL);
+ break;
+ case CPU_DYING:
+ case CPU_DYING_FROZEN:
+ disable_percpu_irq(kvm_vgic_global_state.maint_irq);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block vgic_cpu_nb = {
+ .notifier_call = vgic_cpu_notify,
+};
+
+static irqreturn_t vgic_maintenance_handler(int irq, void *data)
+{
+ /*
+ * We cannot rely on the vgic maintenance interrupt to be
+ * delivered synchronously. This means we can only use it to
+ * exit the VM, and we perform the handling of EOIed
+ * interrupts on the exit path (see vgic_process_maintenance).
+ */
+ return IRQ_HANDLED;
+}
+
+static const struct of_device_id vgic_ids[] = {
+ { .compatible = "arm,cortex-a15-gic", .data = vgic_v2_probe, },
+ { .compatible = "arm,cortex-a7-gic", .data = vgic_v2_probe, },
+ { .compatible = "arm,gic-400", .data = vgic_v2_probe, },
+ { .compatible = "arm,gic-v3", .data = vgic_v3_probe, },
+ {},
+};
+
+/**
+ * kvm_vgic_hyp_init: populates the kvm_vgic_global_state variable
+ * according to the host GIC model. Accordingly calls either
+ * vgic_v2/v3_probe which registers the KVM_DEVICE that can be
+ * instantiated by a guest later on .
+ */
+int kvm_vgic_hyp_init(void)
+{
+ const struct of_device_id *matched_id;
+ const int (*vgic_probe)(struct device_node *);
+ struct device_node *vgic_node;
+ int ret;
+
+ vgic_node = of_find_matching_node_and_match(NULL,
+ vgic_ids, &matched_id);
+ if (!vgic_node) {
+ kvm_err("error: no compatible GIC node found\n");
+ return -ENODEV;
+ }
+
+ vgic_probe = matched_id->data;
+ ret = vgic_probe(vgic_node);
+ if (ret)
+ return ret;
+
+ ret = request_percpu_irq(kvm_vgic_global_state.maint_irq,
+ vgic_maintenance_handler,
+ "vgic", kvm_get_running_vcpus());
+ if (ret) {
+ kvm_err("Cannot register interrupt %d\n",
+ kvm_vgic_global_state.maint_irq);
+ return ret;
+ }
+
+ ret = __register_cpu_notifier(&vgic_cpu_nb);
+ if (ret) {
+ kvm_err("Cannot register vgic CPU notifier\n");
+ goto out_free_irq;
+ }
+
+ on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
+
+ return 0;
+
+out_free_irq:
+ free_percpu_irq(kvm_vgic_global_state.maint_irq,
+ kvm_get_running_vcpus());
+ return ret;
+}
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 39/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (37 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 38/45] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init Andre Przywara
` (6 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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 e16bfeb..2bea557 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -198,6 +198,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] 60+ messages in thread
* [PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (38 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 39/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 41/45] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources Andre Przywara
` (5 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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
---
include/kvm/vgic/vgic.h | 7 +-
virt/kvm/arm/vgic/vgic-v2.c | 5 +
virt/kvm/arm/vgic/vgic-v3.c | 5 +
virt/kvm/arm/vgic/vgic.c | 5 +
virt/kvm/arm/vgic/vgic.h | 8 ++
virt/kvm/arm/vgic/vgic_init.c | 213 ++++++++++++++++++++++++++++++++++++++++++
6 files changed, 242 insertions(+), 1 deletion(-)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2bea557..3566393 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -115,6 +115,7 @@ struct vgic_io_device {
struct vgic_dist {
bool in_kernel;
bool ready;
+ bool initialized;
/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
u32 vgic_model;
@@ -198,7 +199,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,
@@ -207,7 +212,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
#define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel))
-#define vgic_initialized(k) (false)
+#define vgic_initialized(k) ((k)->arch.vgic.initialized)
#define vgic_ready(k) ((k)->arch.vgic.ready)
#define vgic_valid_spi(k,i) (((i) >= VGIC_NR_PRIVATE_IRQS) && \
((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 3c3d3a0..47875a2 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -208,6 +208,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 6e93d8f..97cf901 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -196,6 +196,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 2110d95..f8252d4 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -288,6 +288,11 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
bool level)
{
struct kvm_vcpu *vcpu;
+ int ret;
+
+ ret = vgic_lazy_init(kvm);
+ if (ret)
+ return ret;
vcpu = kvm_get_vcpu(kvm, cpuid);
vgic_update_irq_pending(kvm, vcpu, intid, level);
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 0f55d21..fbfc7b9 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -41,6 +41,7 @@ int vgic_v2_dist_access(struct kvm_vcpu *vcpu, bool is_write,
int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v2_enable(struct kvm_vcpu *vcpu);
int vgic_v2_probe(struct device_node *vgic_node);
#ifdef CONFIG_KVM_ARM_VGIC_V3
@@ -55,6 +56,7 @@ int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
int offset, int len, void *val);
void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v3_enable(struct kvm_vcpu *vcpu);
int vgic_v3_probe(struct device_node *vgic_node);
#else
static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
@@ -100,6 +102,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;
@@ -109,6 +115,8 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+int vgic_lazy_init(struct kvm *kvm);
+int vgic_init(struct kvm *kvm);
void kvm_register_vgic_device(unsigned long type);
#endif
diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c
index 80bf283..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)
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 41/45] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (39 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 42/45] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable Andre Przywara
` (4 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
From: Eric Auger <eric.auger@linaro.org>
map_resources is the last initialization step. It is executed on
1st VCPU run. At that stage the code checks the userspace has provided
the base addresses for the relevant VGIC regions, which depend on
the type of VGIC that is exposed to the guest.
The function also forces the vgic_init if it has not been executed yet
(only allowed for VGIC v2).
for GICv2, The VGIC CPU interface is mapped onto the GIC virtual CPU
interface.
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
include/kvm/vgic/vgic.h | 1 +
virt/kvm/arm/vgic/vgic-v2.c | 47 +++++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v3.c | 44 ++++++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic.h | 16 +++++++++++++++
virt/kvm/arm/vgic/vgic_init.c | 27 +++++++++++++++++++++++++
5 files changed, 135 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 3566393..6e5e6d7 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -204,6 +204,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type);
void kvm_vgic_destroy(struct kvm *kvm);
void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
+int kvm_vgic_map_resources(struct kvm *kvm);
int kvm_vgic_hyp_init(void);
int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 47875a2..ad2b3be 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -213,6 +213,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 97cf901..bd868e2 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -201,6 +201,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 fbfc7b9..8fbbe10 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);
@@ -58,6 +61,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)
{
@@ -110,6 +115,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);
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)
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 42/45] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (40 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 41/45] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 43/45] KVM: arm/arm64: vgic-new: Wire up irqfd injection Andre Przywara
` (3 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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 ad2b3be..cbef1af 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -208,9 +208,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 bd868e2..b6dfee4 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -196,9 +196,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] 60+ messages in thread
* [PATCH 43/45] KVM: arm/arm64: vgic-new: Wire up irqfd injection
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (41 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 42/45] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 44/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling Andre Przywara
` (2 subsequent siblings)
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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 | 51 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
create mode 100644 virt/kvm/arm/vgic/vgic_irqfd.c
diff --git a/virt/kvm/arm/vgic/vgic_irqfd.c b/virt/kvm/arm/vgic/vgic_irqfd.c
new file mode 100644
index 0000000..3eee1bd
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic_irqfd.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <trace/events/kvm.h>
+
+int kvm_irq_map_gsi(struct kvm *kvm,
+ struct kvm_kernel_irq_routing_entry *entries,
+ int gsi)
+{
+ return 0;
+}
+
+int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
+{
+ return pin;
+}
+
+int kvm_set_irq(struct kvm *kvm, int irq_source_id,
+ u32 irq, int level, bool line_status)
+{
+ unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
+
+ trace_kvm_set_irq(irq, level, irq_source_id);
+
+ BUG_ON(!vgic_initialized(kvm));
+
+ return kvm_vgic_inject_irq(kvm, 0, spi, level);
+}
+
+/* MSI not implemented yet */
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+ struct kvm *kvm, int irq_source_id,
+ int level, bool line_status)
+{
+ return 0;
+}
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 44/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (42 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 43/45] KVM: arm/arm64: vgic-new: Wire up irqfd injection Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-15 17:11 ` [PATCH 45/45] KVM: arm/arm64: vgic-new: enable build Andre Przywara
2016-04-18 12:47 ` [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Vladimir Murzin
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 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)
---
include/kvm/vgic/vgic.h | 6 ++++++
virt/kvm/arm/vgic/vgic.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+)
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 6e5e6d7..eff6626 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -209,6 +209,12 @@ int kvm_vgic_hyp_init(void);
int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
bool level);
+/* TODO: for compatibility with the old VGIC's timer implementation */
+#define kvm_vgic_inject_mapped_irq kvm_vgic_inject_irq
+
+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 f8252d4..15fd146 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -17,6 +17,8 @@
#include <linux/kvm.h>
#include <linux/kvm_host.h>
#include <linux/list_sort.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
#include "vgic.h"
@@ -296,6 +298,39 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
vcpu = kvm_get_vcpu(kvm, cpuid);
vgic_update_irq_pending(kvm, vcpu, intid, level);
+
+ return 0;
+}
+
+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;
}
@@ -568,3 +603,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] 60+ messages in thread
* [PATCH 45/45] KVM: arm/arm64: vgic-new: enable build
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (43 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 44/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling Andre Przywara
@ 2016-04-15 17:11 ` Andre Przywara
2016-04-18 12:47 ` [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Vladimir Murzin
45 siblings, 0 replies; 60+ messages in thread
From: Andre Przywara @ 2016-04-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
Now that the new VGIC implementation has reached feature parity with
the old one, add the new files to the build system and add a Kconfig
option to switch between the two versions.
We set the default to the new version to get maximum test coverage,
in case people experience problems they can switch back to the old
behaviour if needed.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
arch/arm/kvm/Kconfig | 7 +++++++
arch/arm/kvm/Makefile | 10 ++++++++++
arch/arm64/kvm/Kconfig | 7 +++++++
arch/arm64/kvm/Makefile | 10 ++++++++++
virt/kvm/arm/hyp/vgic-v2-sr.c | 5 +++++
5 files changed, 39 insertions(+)
diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
index 95a0005..02abfff 100644
--- a/arch/arm/kvm/Kconfig
+++ b/arch/arm/kvm/Kconfig
@@ -46,6 +46,13 @@ config KVM_ARM_HOST
---help---
Provides host support for ARM processors.
+config KVM_NEW_VGIC
+ bool "New VGIC implementation"
+ depends on KVM
+ default y
+ ---help---
+ uses the new VGIC implementation
+
source drivers/vhost/Kconfig
endif # VIRTUALIZATION
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index eb1bf43..aa7d724 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -21,7 +21,17 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp/
obj-y += kvm-arm.o init.o interrupts.o
obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
+
+ifeq ($(CONFIG_KVM_NEW_VGIC),y)
+obj-y += $(KVM)/arm/vgic/vgic.o
+obj-y += $(KVM)/arm/vgic/vgic_init.o
+obj-y += $(KVM)/arm/vgic/vgic_irqfd.o
+obj-y += $(KVM)/arm/vgic/vgic-v2.o
+obj-y += $(KVM)/arm/vgic/vgic_mmio.o
+obj-y += $(KVM)/arm/vgic/vgic_kvm_device.o
+else
obj-y += $(KVM)/arm/vgic.o
obj-y += $(KVM)/arm/vgic-v2.o
obj-y += $(KVM)/arm/vgic-v2-emul.o
+endif
obj-y += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index de7450d..3f0e1ce 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -55,6 +55,13 @@ config KVM_ARM_PMU
Adds support for a virtual Performance Monitoring Unit (PMU) in
virtual machines.
+config KVM_NEW_VGIC
+ bool "New VGIC implementation"
+ depends on KVM
+ default y
+ ---help---
+ uses the new VGIC implementation
+
source drivers/vhost/Kconfig
endif # VIRTUALIZATION
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 122cff4..2f5d431 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -20,10 +20,20 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
+ifeq ($(CONFIG_KVM_NEW_VGIC),y)
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_init.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_irqfd.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_mmio.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_kvm_device.o
+else
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
+endif
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
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] 60+ messages in thread
* [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
` (44 preceding siblings ...)
2016-04-15 17:11 ` [PATCH 45/45] KVM: arm/arm64: vgic-new: enable build Andre Przywara
@ 2016-04-18 12:47 ` Vladimir Murzin
2016-04-19 10:26 ` Andre Przywara
45 siblings, 1 reply; 60+ messages in thread
From: Vladimir Murzin @ 2016-04-18 12:47 UTC (permalink / raw)
To: linux-arm-kernel
Hi Andre,
On 15/04/16 18:11, Andre Przywara wrote:
> Please have a look at the series, review it and give the code some
> serious testing (and possibly debugging). All feedback is appreciated.
I've tried to give it a slight test with --irqchip=gicv3 -c 255, but
even with -c8 I get quite often:
> # lkvm run -k gic-test.flat -m 704 -c 8 --name guest-1167
> 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
>
> Unable to handle kernel paging request at virtual address 3ffc0000
> pgd = ffffffc077ae3000
> [3ffc0000] *pgd=00000000f7989003, *pud=00000000f7989003, *pmd=0000000000000000
> Internal error: Oops: 96000006 [#1] PREEMPT SMP
> Modules linked in:
> CPU: 3 PID: 1176 Comm: kvm-vcpu-1 Tainted: G W 4.6.0-rc3+ #776
> Hardware name: FVP Base (DT)
> task: ffffffc078698c00 ti: ffffffc077b38000 task.ti: ffffffc077b38000
> PC is at vgic_mmio_write_priority+0x38/0x84
> LR is at dispatch_mmio_write+0x64/0x7c
> pc : [<ffffff80080ad868>] lr : [<ffffff80080acb50>] pstate: 20000145
> sp : ffffffc077b3b8f0
> x29: ffffffc077b3b8f0 x28: 0000000000000004
> x27: ffffffc077463b00 x26: ffffffc077913000
> x25: 0000000000000000 x24: 0000000000000000
> x23: 0000000000000004 x22: 000000003ffc0000
> x21: ffffffc077b3ba30 x20: 000000003ffe0400
> x19: 0000000000000000 x18: 0000000000000000
> x17: 0000000000000000 x16: 0000000000000000
> x15: 0000000000000000 x14: 0000000000000000
> x13: 0000000000000000 x12: 0000000000000000
> x11: 000000008015ffd0 x10: 000000008015f660
> x9 : 000000008015f661 x8 : 000000003ffe0404
> x7 : ffffff80080ad830 x6 : ffffffc077b3ba30
> x5 : 0000000000000004 x4 : ffffffc077b3ba30
> x3 : 0000000000000004 x2 : 0000000000000000
> x1 : ffffffc07792e0d0 x0 : ffffffc077463b00
>
> Process kvm-vcpu-1 (pid: 1176, stack limit = 0xffffffc077b38020)
> Stack: (0xffffffc077b3b8f0 to 0xffffffc077b3c000)
> b8e0: ffffffc077b3b930 ffffff80080acb50
> b900: ffffffc07792e0d0 000000003ffe0400 ffffffc077463b00 ffffffc07792f600
> b920: ffffffc077b3b9d8 0000000000000000 ffffffc077b3b970 ffffff80080acd84
> b940: 0000000000000011 ffffffc077463b00 ffffffc077b3ba30 ffffffc077463b00
> b960: 0000000000000004 ffffffc077b3ba30 ffffffc077b3b980 ffffff800809bc2c
> b980: ffffffc077b3b9c0 ffffff800809bccc ffffffc077463b00 0000000000000004
> b9a0: ffffffc077913000 000000003ffe0400 0000000000000004 0000000000000001
> b9c0: ffffffc077b3b9f0 ffffff80080a6a58 0000000000000000 000000003ffe0400
> b9e0: 0000000000000004 0000000000000000 ffffffc077b3ba40 ffffff80080a5c0c
> ba00: 000000003ffe0000 0000000000000000 0000000000000004 000000000003ffe0
> ba20: 0000000000000024 ffffff80080a59cc 00000000a0a0a0a0 00000000a0a0a0a0
> ba40: ffffffc077b3bad0 ffffff80080a7840 ffffffc077463b00 ffffffc077913000
> ba60: 0000000000000001 0000000000000000 ffffffc077464b00 ffffff8008a69000
> ba80: 0000000000000001 ffffffc077b3bb90 ffffffc077913000 ffffff8008af1318
> baa0: ffffffc077b3bab0 ffffff80080ab134 ffffffc077b3bb10 ffffff80080a2a44
> bac0: ffffffc077463b00 0000000000000001 ffffffc077b3bb10 ffffff80080a2a70
> bae0: ffffffc077463b00 0000000000000001 ffffffc077b38000 ffffffc077b3bb90
> bb00: ffffffc077913000 ffffff8008af1318 ffffffc077b3bba0 ffffff800809db88
> bb20: ffffffc0785b2f00 0000000000000000 ffffffc077463b00 0000000000000000
> bb40: ffffffc0779be000 0000000000000000 000000000000011e 000000000000001d
> bb60: ffffff80086f0000 ffffffc077b38000 ffffffc0779be000 ffffff8008af1300
> bb80: ffffffc077463b00 ffffff8008411d18 ffffffc077b3bbc0 0000000000000003
> bba0: ffffffc077b3be00 ffffff80081cae44 ffffffc0779be000 0000000000000000
> bbc0: ffffffc078031920 000000000000000c 000000000000ae80 ffffff80084122a4
> bbe0: ffffffc078734418 000000000000ae80 ffffffc077e5f001 ffffff8008b802a8
> bc00: ffffffc077b3bc10 ffffff8008412340 ffffffc077b3bc40 ffffff8008403d5c
> bc20: ffffffc078734418 ffffffc077e5ec00 ffffffc077e5f001 ffffff8008b802a8
> bc40: ffffffc077b3bc50 ffffff8008403d9c ffffffc077b3bc90 ffffff80080ed7e0
> bc60: ffffffc077b3bc70 ffffff80080eda0c ffffffc077b3bc90 ffffff80083e95f8
> bc80: ffffffc077b3bc90 ffffff80083e9600 ffffffc077b3bce0 ffffff80080eda58
> bca0: ffffffc077e5ee30 0000000000000140 00000000004c995d 0000000000000001
> bcc0: ffffffc0778f5800 0000000000000001 ffffffc077b3bce0 ffffff80080eda64
> bce0: ffffffc077b3bd20 ffffff80083e4114 ffffffc077e5ec00 ffffffc0785e0508
> bd00: ffffffc077b38000 0000000000000004 0000000000000001 0000000000000001
> bd20: ffffffc077b3bd30 ffffff80083ed098 ffffffc077b3bd40 ffffff80083e50b0
> bd40: ffffffc077b3bdb0 ffffff80081b8618 ffffffc0778f5800 ffffffc077b3bec8
> bd60: 00000000004c995c ffffffc077b3bec8 0000000080000000 0000000000000015
> bd80: 000000000000011e 0000000000000040 ffffffc077b3be30 ffffff80081b9588
> bda0: ffffffc0778f5800 0000000000000001 ffffffc0785e0508 0000000000000002
> bdc0: ffffffc0778f5810 0000000000000015 000000000000011e 0000000000000040
> bde0: ffffff80086f0000 ffffffc077b38000 ffffffc077b3be30 00000000081b956c
> be00: ffffffc077b3be90 ffffff80081cb574 0000000000000000 ffffffc0779be001
> be20: ffffffc0779be000 000000000000000c 000000000000ae80 ffffff80081ba828
> be40: ffffffc077b3be70 ffffff80081d5458 ffffffc077b3be90 ffffff80081cb530
> be60: 0000000000000000 ffffffc0779be001 ffffffc0779be000 000000000000000c
> be80: 000000000000ae80 ffffff80081cb514 0000000000000000 ffffff8008085e70
> bea0: 0000000000000000 0000000000493444 ffffffffffffffff 000000000044734c
> bec0: 0000000060000000 0000000000000015 000000000000000c 000000000000ae80
> bee0: 0000000000000000 0000000000000000 0000000000000000 00000000ffffffff
> bf00: 0000007f64180000 0000000000000000 000000000000001d 000000000e461000
> bf20: 0000000000000000 0000007f61171850 0000007f61171850 0000007f61171820
> bf40: ffffff80ffffffd0 0000000000573000 0000000000000000 0000000000000001
> bf60: 0000000000000000 000000000e464b60 0000000000493444 000000000000ffff
> bf80: 0000007fe582d3f8 0000000000000001 0000000000000000 0000000000800000
> bfa0: 0000007fe582d3f8 0000000000001000 0000000000401f68 0000007f61171790
> bfc0: 0000000000406130 0000007f61171790 000000000044734c 0000000060000000
> bfe0: 000000000000000c 000000000000001d cfdfdfdfdfdfdfcf cfdfdfdfdfdfdfcf
> Call trace:
> Exception stack(0xffffffc077b3b730 to 0xffffffc077b3b850)
> b720: 0000000000000000 000000003ffe0400
> b740: ffffffc077b3b8f0 ffffff80080ad868 ffffffc077b3b8e0 ffffff80080e79fc
> b760: 00000000ffff0b21 0000000000000001 ffffffc078422200 0000000000000003
> b780: ffffff8008a5d000 0000000000000001 ffffffc078421300 ffffffc077b3bb90
> b7a0: ffffff8008a5d000 ffffffc077b3b9a8 ffffffc000000000 ffffff80080dba68
> b7c0: ffffffc077b3b830 fffffffffffffff8 ffffffc077463b00 ffffffc07792e0d0
> b7e0: 0000000000000000 0000000000000004 ffffffc077b3ba30 0000000000000004
> b800: ffffffc077b3ba30 ffffff80080ad830 000000003ffe0404 000000008015f661
> b820: 000000008015f660 000000008015ffd0 0000000000000000 0000000000000000
> b840: 0000000000000000 0000000000000000
> [<ffffff80080ad868>] vgic_mmio_write_priority+0x38/0x84
> [<ffffff80080acb50>] dispatch_mmio_write+0x64/0x7c
> [<ffffff80080acd84>] vgic_mmio_write_v3redist_private+0x2c/0x34
> [<ffffff800809bc2c>] __kvm_io_bus_write+0xb8/0x11c
> [<ffffff800809bccc>] kvm_io_bus_write+0x3c/0x4c
> [<ffffff80080a6a58>] io_mem_abort+0x1b0/0x28c
> [<ffffff80080a5c0c>] kvm_handle_guest_abort+0x300/0x680
> [<ffffff80080a7840>] handle_exit+0x5c/0x150
> [<ffffff80080a2a70>] kvm_arch_vcpu_ioctl_run+0x290/0x47c
> [<ffffff800809db88>] kvm_vcpu_ioctl+0x2d4/0x6ec
> [<ffffff80081cae44>] do_vfs_ioctl+0xb4/0x760
> [<ffffff80081cb574>] SyS_ioctl+0x84/0x98
> [<ffffff8008085e70>] el0_svc_naked+0x24/0x28
> Code: 5400022d aa0403f5 0b030057 2a0203f3 (f94002c0)
> ---[ end trace 9d998e161d0dbdb6 ]---
or something like that (I've seen NULL pointer dereference with -c2) but
with the same call trace. It happens only with --irqchip=gicv3, gicv2
works fine.
Code around PC at vgic_mmio_write_priority+0x38/0x84 matches to:
> if (iodev->redist_vcpu)
> ffffff80080ad848: f85f8036 ldr x22, [x1,#-8]
> ffffff80080ad84c: eb1f02df cmp x22, xzr
> ffffff80080ad850: 9a8012d6 csel x22, x22, x0, ne
> vcpu = iodev->redist_vcpu;
>
> for (i = 0; i < len; i++) {
> ffffff80080ad854: 6b1f007f cmp w3, wzr
> ffffff80080ad858: 5400022d b.le ffffff80080ad89c <vgic_mmio_write_priority+0x6c>
> ffffff80080ad85c: aa0403f5 mov x21, x4
> ffffff80080ad860: 0b030057 add w23, w2, w3
> ffffff80080ad864: 2a0203f3 mov w19, w2
> struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> ffffff80080ad868: f94002c0 ldr x0, [x22]
> ffffff80080ad86c: 2a1303e2 mov w2, w19
> ffffff80080ad870: aa1603e1 mov x1, x22
> ffffff80080ad874: 11000673 add w19, w19, #0x1
> ffffff80080ad878: 97fff4d0 bl ffffff80080aabb8 <vgic_get_irq>
> ffffff80080ad87c: aa0003f4 mov x20, x0
Cheers
Vladimir
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
2016-04-18 12:47 ` [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Vladimir Murzin
@ 2016-04-19 10:26 ` Andre Przywara
2016-04-19 12:04 ` Vladimir Murzin
0 siblings, 1 reply; 60+ messages in thread
From: Andre Przywara @ 2016-04-19 10:26 UTC (permalink / raw)
To: linux-arm-kernel
Hi Vladimir,
can you try the attached patch on top of the series to see if this
fixes the GICv3 emulation issues you see?
I think these lines got lost during the MMIO framework rebasing.
Cheers,
Andre.
---
virt/kvm/arm/vgic/vgic_mmio.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
index ec96188..92f39ba 100644
--- a/virt/kvm/arm/vgic/vgic_mmio.c
+++ b/virt/kvm/arm/vgic/vgic_mmio.c
@@ -1228,6 +1228,7 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
kvm_for_each_vcpu(c, vcpu, kvm) {
kvm_iodevice_init(®ion->dev, &kvm_io_v3redist_ops);
region->base_addr = redist_base_address;
+ region->redist_vcpu = vcpu;
mutex_lock(&kvm->slots_lock);
ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
@@ -1241,6 +1242,7 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
region++;
kvm_iodevice_init(®ion->dev, &kvm_io_v3redist_private_ops);
region->base_addr = redist_base_address + SZ_64K;
+ region->redist_vcpu = vcpu;
mutex_lock(&kvm->slots_lock);
ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
--
2.7.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation
2016-04-19 10:26 ` Andre Przywara
@ 2016-04-19 12:04 ` Vladimir Murzin
0 siblings, 0 replies; 60+ messages in thread
From: Vladimir Murzin @ 2016-04-19 12:04 UTC (permalink / raw)
To: linux-arm-kernel
On 19/04/16 11:26, Andre Przywara wrote:
> Hi Vladimir,
>
> can you try the attached patch on top of the series to see if this
> fixes the GICv3 emulation issues you see?
>
With attached patch I don't see issue any more - all 255 vcpus are able
to boot and send/receive self SGI.
Thanks
Vladimir
> I think these lines got lost during the MMIO framework rebasing.
>
> Cheers,
> Andre.
>
> ---
> virt/kvm/arm/vgic/vgic_mmio.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index ec96188..92f39ba 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -1228,6 +1228,7 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
> kvm_for_each_vcpu(c, vcpu, kvm) {
> kvm_iodevice_init(®ion->dev, &kvm_io_v3redist_ops);
> region->base_addr = redist_base_address;
> + region->redist_vcpu = vcpu;
>
> mutex_lock(&kvm->slots_lock);
> ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> @@ -1241,6 +1242,7 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
> region++;
> kvm_iodevice_init(®ion->dev, &kvm_io_v3redist_private_ops);
> region->base_addr = redist_base_address + SZ_64K;
> + region->redist_vcpu = vcpu;
>
> mutex_lock(&kvm->slots_lock);
> ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
2016-04-15 17:11 ` [PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers Andre Przywara
@ 2016-04-19 12:26 ` Peter Maydell
0 siblings, 0 replies; 60+ messages in thread
From: Peter Maydell @ 2016-04-19 12:26 UTC (permalink / raw)
To: linux-arm-kernel
On 15 April 2016 at 18:11, Andre Przywara <andre.przywara@arm.com> wrote:
> 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
> ---
> virt/kvm/arm/vgic/vgic.h | 2 ++
> virt/kvm/arm/vgic/vgic_mmio.c | 56 ++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 57 insertions(+), 1 deletion(-)
>
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index ccae13e..83b342c 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,
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 4a31d60..a87bbca 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -686,6 +686,60 @@ static int vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
> return 0;
> }
>
> +/*****************************/
> +/* GICv3 emulation functions */
> +/*****************************/
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +
> +static int vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
> + struct kvm_io_device *dev,
> + gpa_t addr, int len, void *val)
> +{
> + u32 value = 0;
> +
> + switch (addr & 0x0c) {
> + case GICD_CTLR:
> + if (vcpu->kvm->arch.vgic.enabled)
> + value |= GICD_CTLR_ENABLE_SS_G1;
...what about the EnableGrp0 bit ? You're a single-security-State
GIC (since you advertise DS==1), so you should have two enable bits here.
> + 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;
Are you deliberately claiming support for 1-of-N SPI interrupts (No1N == 0) ?
Is A3V==0 (no support for non-zero Aff3) correct? Is it a restriction we
might lift in future?
> + break;
> + case GICD_IIDR:
> + value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> + break;
> + default:
> + return 0;
> + }
> +
> + write_mask32(value, addr & 3, len, val);
> + return 0;
> +}
> +
> +static int vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
> + struct kvm_io_device *dev,
> + gpa_t addr, int len, const void *val)
> +{
> + struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> + bool was_enabled = dist->enabled;
> +
> + /* Of the whole region only the first byte is actually writeable. */
> + if ((addr & 0x0f) > 0)
> + return 0;
> +
> + /* We only care about the enable bit, all other bits are WI. */
> + dist->enabled = *(u8*)val & GICD_CTLR_ENABLE_SS_G1;
Again, there are two enable bits here.
Also, this is a 32-bit register, so how does the *(u8*) work?
> +
> + if (!was_enabled && dist->enabled)
> + vgic_kick_vcpus(vcpu->kvm);
> +
> + return 0;
> +}
> +
> +
> /*
> * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
> * redistributors, while SPIs are covered by registers in the distributor
> @@ -734,7 +788,7 @@ struct vgic_register_region vgic_v2_dist_registers[] = {
> #ifdef CONFIG_KVM_ARM_VGIC_V3
> struct vgic_register_region vgic_v3_dist_registers[] = {
> REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> - vgic_mmio_read_nyi, vgic_mmio_write_nyi, 16),
> + vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
...and here it says 16, which is neither 8 nor 32...
> 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,
> --
> 2.7.3
thanks
-- PMM
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
2016-04-15 17:11 ` [PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler Andre Przywara
@ 2016-04-19 12:34 ` Peter Maydell
2016-04-19 12:57 ` André Przywara
0 siblings, 1 reply; 60+ messages in thread
From: Peter Maydell @ 2016-04-19 12:34 UTC (permalink / raw)
To: linux-arm-kernel
On 15 April 2016 at 18:11, Andre Przywara <andre.przywara@arm.com> wrote:
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> virt/kvm/arm/vgic/vgic_mmio.c | 21 +++++++++++++++++++--
> 1 file changed, 19 insertions(+), 2 deletions(-)
>
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index 7d275a7..dafa235 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -784,6 +784,23 @@ static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
> return 0;
> }
>
> +static int vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
> + struct kvm_io_device *dev,
> + gpa_t addr, int len, void *val)
> +{
> + 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;
> + }
We claim to be an ARM implementation, so we should report the full
set of ARM ID registers, not just GICD_PIDR2:
0x44, 0x00, 0x00, 0x00, 0x92, 0xB4, 0x3B, 0x00, 0x0D, 0xF0, 0x05, 0xB1
(starting at 0xFFD0 and going up to 0xFFFC.)
> + write_mask32(reg , addr & 3, len, val);
> + return 0;
> +}
> #endif
thanks
-- PMM
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
2016-04-15 17:11 ` [PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler Andre Przywara
@ 2016-04-19 12:40 ` Peter Maydell
0 siblings, 0 replies; 60+ messages in thread
From: Peter Maydell @ 2016-04-19 12:40 UTC (permalink / raw)
To: linux-arm-kernel
On 15 April 2016 at 18:11, Andre Przywara <andre.przywara@arm.com> wrote:
> In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
> by a MMIO write, but with a system register write. KVM knows about
> that register already, we just need to implement the handler and wire
> it up to the core KVM/ARM code.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>
> Changelog RFC..v1:
> - add comment about SGI_AFFINITY_LEVEL macro
> +/**
> + * 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.
> + */
No ICC_SGI0R_EL1, ICC_ASGI1R_EL1 ?
> +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);
> + }
I think you need a check in here that the SGI is actually configured
to be the group that's been requested.
> +
> + irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
> +
> + spin_lock(&irq->irq_lock);
> + irq->pending = true;
> +
> + vgic_queue_irq_unlock(vcpu->kvm, irq);
> + }
> +}
> #endif
> --
> 2.7.3
thanks
-- PMM
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
2016-04-19 12:34 ` Peter Maydell
@ 2016-04-19 12:57 ` André Przywara
2016-04-19 13:12 ` Peter Maydell
0 siblings, 1 reply; 60+ messages in thread
From: André Przywara @ 2016-04-19 12:57 UTC (permalink / raw)
To: linux-arm-kernel
Hi Peter,
thanks for going through the pain of looking into this!
On 19/04/16 13:34, Peter Maydell wrote:
> On 15 April 2016 at 18:11, Andre Przywara <andre.przywara@arm.com> wrote:
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> virt/kvm/arm/vgic/vgic_mmio.c | 21 +++++++++++++++++++--
>> 1 file changed, 19 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
>> index 7d275a7..dafa235 100644
>> --- a/virt/kvm/arm/vgic/vgic_mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
>> @@ -784,6 +784,23 @@ static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
>> return 0;
>> }
>>
>> +static int vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
>> + struct kvm_io_device *dev,
>> + gpa_t addr, int len, void *val)
>> +{
>> + 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;
>> + }
>
> We claim to be an ARM implementation, so we should report the full
> set of ARM ID registers, not just GICD_PIDR2:
Do we really have to? Please note that though we say our implementor is
ARM (because we lack alternatives, I think), we don't claim to be a
GIC-500, for instance, but a made-up KVM implementation.
So there is no need to implement the other ID registers, except for the
architecturally defined PIDR2, which Linux actually checks to confirm
that this is a GICv3 compliant GIC.
> 0x44, 0x00, 0x00, 0x00, 0x92, 0xB4, 0x3B, 0x00, 0x0D, 0xF0, 0x05, 0xB1
Yes, I had those registers defined like this in an earlier version, but
Marc's comment IIRC correctly was that we shouldn't claim to be a
GIC-500, for instance, because then we would need to mimic GIC-500
behavior quite closely, which we simply don't and also don't want to.
So architecturally we are fine, I think.
Do you think by claiming coming from ARM we are obliged to implement all
the other PIDR/CIDR registers the ARM way?
Cheers,
Andre.
>
> (starting at 0xFFD0 and going up to 0xFFFC.)
>
>> + write_mask32(reg , addr & 3, len, val);
>> + return 0;
>> +}
>> #endif
>
> thanks
> -- PMM
>
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
2016-04-19 12:57 ` André Przywara
@ 2016-04-19 13:12 ` Peter Maydell
0 siblings, 0 replies; 60+ messages in thread
From: Peter Maydell @ 2016-04-19 13:12 UTC (permalink / raw)
To: linux-arm-kernel
On 19 April 2016 at 13:57, Andr? Przywara <andre.przywara@arm.com> wrote:
> Hi Peter,
>
> thanks for going through the pain of looking into this!
No problem -- I figured I might as well while I have my head full
of the GICv3 spec for the QEMU emulated version.
> On 19/04/16 13:34, Peter Maydell wrote:
>> We claim to be an ARM implementation, so we should report the full
>> set of ARM ID registers, not just GICD_PIDR2:
>
> Do we really have to? Please note that though we say our implementor is
> ARM (because we lack alternatives, I think), we don't claim to be a
> GIC-500, for instance, but a made-up KVM implementation.
> So there is no need to implement the other ID registers, except for the
> architecturally defined PIDR2, which Linux actually checks to confirm
> that this is a GICv3 compliant GIC.
>
>> 0x44, 0x00, 0x00, 0x00, 0x92, 0xB4, 0x3B, 0x00, 0x0D, 0xF0, 0x05, 0xB1
>
> Yes, I had those registers defined like this in an earlier version, but
> Marc's comment IIRC correctly was that we shouldn't claim to be a
> GIC-500, for instance, because then we would need to mimic GIC-500
> behavior quite closely, which we simply don't and also don't want to.
This isn't claiming to be a GIC-500 (which you would do via the
GICD_IIDR and GICR_IIDR by specifying the right Product field).
This is implementing the Coresight ID registers, which the spec
says have the same values for all ARM implementations (and as you
note, you are claiming in the IIDR registers to be an ARM
implementation). The spec also says "ARM strongly recommends that
other implementers also use this scheme", so even if we weren't
saying we were an ARM implementation I think it would be a good idea.
> Do you think by claiming coming from ARM we are obliged to implement all
> the other PIDR/CIDR registers the ARM way?
I think so, and it's not exactly difficult so why not?
Any guest that thinks these ID values mean "I'm a GIC-500" is
broken :-)
thanks
-- PMM
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
2016-04-15 17:11 ` [PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance Andre Przywara
@ 2016-04-25 16:15 ` Andrew Jones
2016-04-25 19:49 ` Christoffer Dall
0 siblings, 1 reply; 60+ messages in thread
From: Andrew Jones @ 2016-04-25 16:15 UTC (permalink / raw)
To: linux-arm-kernel
Hi Andre,
I'm just randomly jumping in here because I spotted a typo in $SUBJECT.
'accessor' has too many c's. Also, just curious, but if the author is
from Linaro (hi Christoffer), then why do the new files this patch adds
have ARM copyrights?
Thanks,
drew
On Fri, Apr 15, 2016 at 06:11:16PM +0100, Andre Przywara wrote:
> 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
>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
2016-04-25 16:15 ` Andrew Jones
@ 2016-04-25 19:49 ` Christoffer Dall
2016-04-26 8:21 ` Marc Zyngier
0 siblings, 1 reply; 60+ messages in thread
From: Christoffer Dall @ 2016-04-25 19:49 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Apr 25, 2016 at 06:15:25PM +0200, Andrew Jones wrote:
> Hi Andre,
>
> I'm just randomly jumping in here because I spotted a typo in $SUBJECT.
> 'accessor' has too many c's. Also, just curious, but if the author is
> from Linaro (hi Christoffer), then why do the new files this patch adds
> have ARM copyrights?
>
We just decided to let ARM deal with asserting the license since we all
collaborated on it, but others also suggested that we should let ARM and
Linaro share the license.
-Christoffer
>
> On Fri, Apr 15, 2016 at 06:11:16PM +0100, Andre Przywara wrote:
> > 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
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe kvm" in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
2016-04-25 19:49 ` Christoffer Dall
@ 2016-04-26 8:21 ` Marc Zyngier
2016-04-26 9:44 ` Andrew Jones
0 siblings, 1 reply; 60+ messages in thread
From: Marc Zyngier @ 2016-04-26 8:21 UTC (permalink / raw)
To: linux-arm-kernel
On 25/04/16 20:49, Christoffer Dall wrote:
> On Mon, Apr 25, 2016 at 06:15:25PM +0200, Andrew Jones wrote:
>> Hi Andre,
>>
>> I'm just randomly jumping in here because I spotted a typo in $SUBJECT.
>> 'accessor' has too many c's. Also, just curious, but if the author is
>> from Linaro (hi Christoffer), then why do the new files this patch adds
>> have ARM copyrights?
>>
>
> We just decided to let ARM deal with asserting the license since we all
> collaborated on it, but others also suggested that we should let ARM and
> Linaro share the license.
I personally have no objections to having both ARM and Linaro sharing
the copyright, but I just don't know how this works in practice (and
asking any legal department is a sure recipe to delay these patches for
an extra 6 months, give or take a few years).
In the end, all I care about is the licence under which the code is
released.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
2016-04-26 8:21 ` Marc Zyngier
@ 2016-04-26 9:44 ` Andrew Jones
2016-04-26 18:42 ` Christoffer Dall
0 siblings, 1 reply; 60+ messages in thread
From: Andrew Jones @ 2016-04-26 9:44 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Apr 26, 2016 at 09:21:30AM +0100, Marc Zyngier wrote:
> On 25/04/16 20:49, Christoffer Dall wrote:
> > On Mon, Apr 25, 2016 at 06:15:25PM +0200, Andrew Jones wrote:
> >> Hi Andre,
> >>
> >> I'm just randomly jumping in here because I spotted a typo in $SUBJECT.
> >> 'accessor' has too many c's. Also, just curious, but if the author is
> >> from Linaro (hi Christoffer), then why do the new files this patch adds
> >> have ARM copyrights?
> >>
> >
> > We just decided to let ARM deal with asserting the license since we all
> > collaborated on it, but others also suggested that we should let ARM and
> > Linaro share the license.
>
> I personally have no objections to having both ARM and Linaro sharing
> the copyright, but I just don't know how this works in practice (and
> asking any legal department is a sure recipe to delay these patches for
> an extra 6 months, give or take a few years).
>
> In the end, all I care about is the licence under which the code is
> released.
>
Thanks, my curiosity is satisfied. I fully agree that if it's not easy
to share a collaborated file, then it's just a matter of flipping a coin,
or defaulting to whichever has the majority.
drew
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
2016-04-15 17:11 ` [PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Andre Przywara
@ 2016-04-26 10:14 ` Marc Zyngier
0 siblings, 0 replies; 60+ messages in thread
From: Marc Zyngier @ 2016-04-26 10:14 UTC (permalink / raw)
To: linux-arm-kernel
On 15/04/16 18:11, Andre Przywara wrote:
> Describe the GICv3 distributor and redistributor registers in our
> structure. This adds a special macro to deal with the split of
> SGI/PPI in the redistributor and SPIs in the distributor, which
> allows us to reuse the existing GICv2 handlers for those registers
> which are compatible.
> Also we register the separate MMIO page for the redistributor
> registers dealing with private interrupts.
>
> 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
> ---
> virt/kvm/arm/vgic/vgic.h | 16 +++
> virt/kvm/arm/vgic/vgic_mmio.c | 269 ++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 285 insertions(+)
>
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 59fddbf..ccae13e 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -40,6 +40,10 @@ 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);
> +int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> + int offset, int len, void *val);
> +int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
> + int offset, int len, void *val);
> #else
> static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> {
> @@ -61,6 +65,18 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
> static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> {
> }
> +
> +static inline int vgic_v3_dist_access(struct kvm_vcpu *vcpu, bool is_write,
> + int offset, int len, void *val)
> +{
> + return -ENXIO;
> +}
> +
> +static inline int vgic_v3_redist_access(struct kvm_vcpu *vcpu, bool is_write,
> + int offset, int len, void *val)
> +{
> + return -ENXIO;
> +}
> #endif
>
> #endif
> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c
> index daa2e00..4a31d60 100644
> --- a/virt/kvm/arm/vgic/vgic_mmio.c
> +++ b/virt/kvm/arm/vgic/vgic_mmio.c
> @@ -17,6 +17,8 @@
> #include <kvm/vgic/vgic.h>
> #include <linux/bitops.h>
> #include <linux/irqchip/arm-gic.h>
> +#include <linux/irqchip/arm-gic-v3.h>
This is going to cause no end of trouble in the long run. There two
include files were never designed to co-exist, and it is only a matter
of chance if they do not clash.
I'm afraid we'll eventually need to split that file in vgic-mmio.c,
vgic-mmio-v2.c and vgic-mmio-v3.c.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
2016-04-26 9:44 ` Andrew Jones
@ 2016-04-26 18:42 ` Christoffer Dall
0 siblings, 0 replies; 60+ messages in thread
From: Christoffer Dall @ 2016-04-26 18:42 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Apr 26, 2016 at 11:44:33AM +0200, Andrew Jones wrote:
> On Tue, Apr 26, 2016 at 09:21:30AM +0100, Marc Zyngier wrote:
> > On 25/04/16 20:49, Christoffer Dall wrote:
> > > On Mon, Apr 25, 2016 at 06:15:25PM +0200, Andrew Jones wrote:
> > >> Hi Andre,
> > >>
> > >> I'm just randomly jumping in here because I spotted a typo in $SUBJECT.
> > >> 'accessor' has too many c's. Also, just curious, but if the author is
> > >> from Linaro (hi Christoffer), then why do the new files this patch adds
> > >> have ARM copyrights?
> > >>
> > >
> > > We just decided to let ARM deal with asserting the license since we all
> > > collaborated on it, but others also suggested that we should let ARM and
> > > Linaro share the license.
> >
> > I personally have no objections to having both ARM and Linaro sharing
> > the copyright, but I just don't know how this works in practice (and
> > asking any legal department is a sure recipe to delay these patches for
> > an extra 6 months, give or take a few years).
> >
> > In the end, all I care about is the licence under which the code is
> > released.
> >
>
> Thanks, my curiosity is satisfied. I fully agree that if it's not easy
> to share a collaborated file, then it's just a matter of flipping a coin,
> or defaulting to whichever has the majority.
>
I also only care about the license under which it is released.
I opted for defaulting to the company that is most set up to pursue any
potential infringement on the copyright.
-Christoffer
^ permalink raw reply [flat|nested] 60+ messages in thread
end of thread, other threads:[~2016-04-26 18:42 UTC | newest]
Thread overview: 60+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-04-15 17:11 [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
2016-04-15 17:11 ` [PATCH 01/45] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr Andre Przywara
2016-04-15 17:11 ` [PATCH 02/45] KVM: arm/arm64: Fix MMIO emulation data handling Andre Przywara
2016-04-15 17:11 ` [PATCH 03/45] KVM: arm/arm64: pmu: abstract access to number of SPIs Andre Przywara
2016-04-15 17:11 ` [PATCH 04/45] KVM: arm/arm64: vgic-new: Add data structure definitions Andre Przywara
2016-04-15 17:11 ` [PATCH 05/45] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance Andre Przywara
2016-04-25 16:15 ` Andrew Jones
2016-04-25 19:49 ` Christoffer Dall
2016-04-26 8:21 ` Marc Zyngier
2016-04-26 9:44 ` Andrew Jones
2016-04-26 18:42 ` Christoffer Dall
2016-04-15 17:11 ` [PATCH 06/45] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection Andre Przywara
2016-04-15 17:11 ` [PATCH 07/45] KVM: arm/arm64: vgic-new: Add IRQ sorting Andre Przywara
2016-04-15 17:11 ` [PATCH 08/45] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework Andre Przywara
2016-04-15 17:11 ` [PATCH 09/45] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend Andre Przywara
2016-04-15 17:11 ` [PATCH 10/45] KVM: arm/arm64: vgic-new: Add GICv3 " Andre Przywara
2016-04-15 17:11 ` [PATCH 11/45] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq Andre Przywara
2016-04-15 17:11 ` [PATCH 12/45] KVM: arm/arm64: vgic-new: Add MMIO handling framework Andre Przywara
2016-04-15 17:11 ` [PATCH 13/45] KVM: arm/arm64: vgic-new: Export register access interface Andre Przywara
2016-04-15 17:11 ` [PATCH 14/45] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers Andre Przywara
2016-04-15 17:11 ` [PATCH 15/45] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers Andre Przywara
2016-04-15 17:11 ` [PATCH 16/45] KVM: arm/arm64: vgic-new: Add PENDING " Andre Przywara
2016-04-15 17:11 ` [PATCH 17/45] KVM: arm/arm64: vgic-new: Add PRIORITY " Andre Przywara
2016-04-15 17:11 ` [PATCH 18/45] KVM: arm/arm64: vgic-new: Add ACTIVE " Andre Przywara
2016-04-15 17:11 ` [PATCH 19/45] KVM: arm/arm64: vgic-new: Add CONFIG " Andre Przywara
2016-04-15 17:11 ` [PATCH 20/45] KVM: arm/arm64: vgic-new: Add TARGET " Andre Przywara
2016-04-15 17:11 ` [PATCH 21/45] KVM: arm/arm64: vgic-new: Add SGIR register handler Andre Przywara
2016-04-15 17:11 ` [PATCH 22/45] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers Andre Przywara
2016-04-15 17:11 ` [PATCH 23/45] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Andre Przywara
2016-04-26 10:14 ` Marc Zyngier
2016-04-15 17:11 ` [PATCH 24/45] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers Andre Przywara
2016-04-19 12:26 ` Peter Maydell
2016-04-15 17:11 ` [PATCH 25/45] KVM: arm/arm64: vgic-new: Add GICv3 redistributor " Andre Przywara
2016-04-15 17:11 ` [PATCH 26/45] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler Andre Przywara
2016-04-19 12:34 ` Peter Maydell
2016-04-19 12:57 ` André Przywara
2016-04-19 13:12 ` Peter Maydell
2016-04-15 17:11 ` [PATCH 27/45] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers Andre Przywara
2016-04-15 17:11 ` [PATCH 28/45] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler Andre Przywara
2016-04-19 12:40 ` Peter Maydell
2016-04-15 17:11 ` [PATCH 29/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration Andre Przywara
2016-04-15 17:11 ` [PATCH 30/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS Andre Przywara
2016-04-15 17:11 ` [PATCH 31/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL Andre Przywara
2016-04-15 17:11 ` [PATCH 32/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR Andre Przywara
2016-04-15 17:11 ` [PATCH 33/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers Andre Przywara
2016-04-15 17:11 ` [PATCH 34/45] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr Andre Przywara
2016-04-15 17:11 ` [PATCH 35/45] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers Andre Przywara
2016-04-15 17:11 ` [PATCH 36/45] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors Andre Przywara
2016-04-15 17:11 ` [PATCH 37/45] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access Andre Przywara
2016-04-15 17:11 ` [PATCH 38/45] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init Andre Przywara
2016-04-15 17:11 ` [PATCH 39/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create Andre Przywara
2016-04-15 17:11 ` [PATCH 40/45] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init Andre Przywara
2016-04-15 17:11 ` [PATCH 41/45] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources Andre Przywara
2016-04-15 17:11 ` [PATCH 42/45] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable Andre Przywara
2016-04-15 17:11 ` [PATCH 43/45] KVM: arm/arm64: vgic-new: Wire up irqfd injection Andre Przywara
2016-04-15 17:11 ` [PATCH 44/45] KVM: arm/arm64: vgic-new: implement mapped IRQ handling Andre Przywara
2016-04-15 17:11 ` [PATCH 45/45] KVM: arm/arm64: vgic-new: enable build Andre Przywara
2016-04-18 12:47 ` [PATCH 00/45] KVM: arm/arm64: Rework virtual GIC emulation Vladimir Murzin
2016-04-19 10:26 ` Andre Przywara
2016-04-19 12:04 ` Vladimir Murzin
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).