* [PATCH v3 00/12] Virtual GIC save/restore optimization
@ 2016-03-07 9:33 Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 01/12] KVM: arm/arm64: vgic-v2: Avoid accessing GICH registers Marc Zyngier
` (11 more replies)
0 siblings, 12 replies; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
I've recently been looking at our entry/exit costs, and profiling
figures did show some very low hanging fruits.
The most obvious cost is that accessing the GIC HW is slow. As in
"deadly slow", specially when GICv2 is involved. So not hammering the
HW when there is nothing to write (and even to read) is immediately
beneficial, as this is the most common cases (whatever people seem to
think, interrupts are a *rare* event). Similar work has also been done
for GICv3, with a reduced impact (it was less "bad" to start with).
Another easy thing to fix is the way we handle trapped system
registers. We do insist on (mostly) sorting them, but we do perform a
linear search on trap. We can switch to a binary search for free, and
get immediate benefits (the PMU code, being extremely trap-happy,
benefits immediately from this).
With these in place, I see an improvement of 10 to 40% (depending on
the platform) on our world-switch cycle count when running a set of
hand-crafted guests that are designed to only perform traps.
Please note that VM exits are actually a rare event on ARM. So don't
expect your guest to be 40% faster, this will hardly make a noticable
difference.
Methodology:
* NULL-hypercall guest: Perform 2^20 PSCI_0_2_FN_PSCI_VERSION calls,
and then a power-off:
__start:
mov x19, #(1 << 20)
1: mov x0, #0x84000000
hvc #0
sub x19, x19, #1
cbnz x19, 1b
mov x0, #0x84000000
add x0, x0, #9
hvc #0
b .
* Self IPI guest: Inject and handle 2^20 SGI0 using GICv2 or GICv3,
and then power-off:
__start:
mov x19, #(1 << 20)
mrs x0, id_aa64pfr0_el1
ubfx x0, x0, #24, #4
and x0, x0, #0xf
cbz x0, do_v2
mrs x0, s3_0_c12_c12_5 // ICC_SRE_EL1
and x0, x0, #1 // SRE bit
cbnz x0, do_v3
do_v2:
mov x0, #0x3fff0000 // Dist
mov x1, #0x3ffd0000 // CPU
mov w2, #1
str w2, [x0] // Enable Group0
ldr w2, =0xa0a0a0a0
str w2, [x0, 0x400] // A0 priority for SGI0-3
mov w2, #0x0f
str w2, [x0, #0x100] // Enable SGI0-3
mov w2, #0xf0
str w2, [x1, #4] // PMR
mov w2, #1
str w2, [x1] // Enable CPU interface
1:
mov w2, #(2 << 24) // Interrupt self with SGI0
str w2, [x0, #0xf00]
2: ldr w2, [x1, #0x0c] // GICC_IAR
cmp w2, #0x3ff
b.ne 3f
wfi
b 2b
3: str w2, [x1, #0x10] // EOI
sub x19, x19, #1
cbnz x19, 1b
die:
mov x0, #0x84000000
add x0, x0, #9
hvc #0
b .
do_v3:
mov x0, #0x3fff0000 // Dist
mov x1, #0x3fbf0000 // Redist 0
mov x2, #0x10000
add x1, x1, x2 // SGI page
mov w2, #2
str w2, [x0] // Enable Group1
ldr w2, =0xa0a0a0a0
str w2, [x1, 0x400] // A0 priority for SGI0-3
mov w2, #0x0f
str w2, [x1, #0x100] // Enable SGI0-3
mov w2, #0xf0
msr S3_0_c4_c6_0, x2 // PMR
mov w2, #1
msr S3_0_C12_C12_7, x2 // Enable Group1
1:
mov x2, #1
msr S3_0_c12_c11_5, x2 // Self SGI0
2: mrs x2, S3_0_c12_c12_0 // Read IAR1
cmp w2, #0x3ff
b.ne 3f
wfi
b 2b
3: msr S3_0_c12_c12_1, x2 // EOI
sub x19, x19, #1
cbnz x19, 1b
b die
* sysreg trap guest: Perform 2^20 PMSELR_EL0 accesses, and power-off:
__start:
mov x19, #(1 << 20)
1: mrs x0, PMSELR_EL0
sub x19, x19, #1
cbnz x19, 1b
mov x0, #0x84000000
add x0, x0, #9
hvc #0
b .
* These guests are profiled using perf and kvmtool:
taskset -c 1 perf stat -e cycles:kh lkvm run -c1 --kernel do_sysreg.bin 2>&1 >/dev/null| grep cycles
The result is then divided by the number of iterations (2^20).
These tests have been run on three different platform (two GICv2
based, and one with GICv3 and legacy mode) and shown significant
improvements in all cases. I've only touched the arm64 GIC code, but
obviously the 32bit code should use it as well once we've migrated it
to C.
Vanilla v4.5-rc4
A B C-v2 C-v3
Null HVC: 8462 6566 6572 6505
Self SGI: 11961 8690 9541 8629
SysReg: 8952 6979 7212 7180
Patched v4.5-rc4
A B C-v2 C-v3
Null HVC: 5219 -38% 3957 -39% 5175 -21% 5158 -20%
Self SGI: 8946 -25% 6658 -23% 8547 -10% 7299 -15%
SysReg: 5314 -40% 4190 -40% 5417 -25% 5414 -24%
Thanks,
M.
* From v2:
- Added early init of LRs to make sure we don't get any stale value
at runtime
- Dropped the first few patche that have already been merged
- Dropped the GICv3 ICH_AP0Rn_EL2 optimization as it breaks on the ARMv8
model
- Collected RBs and Acks from Christoffer
* From v1:
- Fixed a nasty bug dealing with the active Priority Register
- Maintenance interrupt lazy saving
- More LR hackery
- Adapted most of the series for GICv3 as well
Marc Zyngier (12):
KVM: arm/arm64: vgic-v2: Avoid accessing GICH registers
KVM: arm/arm64: vgic-v2: Save maintenance interrupt state only if
required
KVM: arm/arm64: vgic-v2: Move GICH_ELRSR saving to its own function
KVM: arm/arm64: vgic-v2: Do not save an LR known to be empty
KVM: arm/arm64: vgic-v2: Reset LRs at boot time
KVM: arm/arm64: vgic-v2: Only wipe LRs on vcpu exit
KVM: arm/arm64: vgic-v2: Make GICD_SGIR quicker to hit
arm64: KVM: vgic-v3: Avoid accessing ICH registers
arm64: KVM: vgic-v3: Save maintenance interrupt state only if required
arm64: KVM: vgic-v3: Do not save an LR known to be empty
arm64: KVM: vgic-v3: Reset LRs at boot time
arm64: KVM: vgic-v3: Only wipe LRs on vcpu exit
arch/arm64/include/asm/kvm_asm.h | 1 +
arch/arm64/kvm/hyp/vgic-v3-sr.c | 337 ++++++++++++++++++++++++++-------------
include/kvm/arm_vgic.h | 8 +-
virt/kvm/arm/hyp/vgic-v2-sr.c | 144 +++++++++++++----
virt/kvm/arm/vgic-v2-emul.c | 10 +-
virt/kvm/arm/vgic-v2.c | 12 ++
virt/kvm/arm/vgic-v3.c | 11 +-
7 files changed, 369 insertions(+), 154 deletions(-)
--
2.1.4
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 01/12] KVM: arm/arm64: vgic-v2: Avoid accessing GICH registers
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 02/12] KVM: arm/arm64: vgic-v2: Save maintenance interrupt state only if required Marc Zyngier
` (10 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
GICv2 registers are *slow*. As in "terrifyingly slow". Which is bad.
But we're equaly bad, as we make a point in accessing them even if
we don't have any interrupt in flight.
A good solution is to first find out if we have anything useful to
write into the GIC, and if we don't, to simply not do it. This
involves tracking which LRs actually have something valid there.
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
include/kvm/arm_vgic.h | 2 ++
virt/kvm/arm/hyp/vgic-v2-sr.c | 72 ++++++++++++++++++++++++++++++-------------
2 files changed, 52 insertions(+), 22 deletions(-)
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 13a3d53..f473fd6 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -321,6 +321,8 @@ struct vgic_cpu {
/* Protected by the distributor's irq_phys_map_lock */
struct list_head irq_phys_map_list;
+
+ u64 live_lrs;
};
#define LR_EMPTY 0xff
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 9514a7d..aa0fdb8 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -36,28 +36,41 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
nr_lr = vcpu->arch.vgic_cpu.nr_lr;
cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
- cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
- eisr0 = readl_relaxed(base + GICH_EISR0);
- elrsr0 = readl_relaxed(base + GICH_ELRSR0);
- if (unlikely(nr_lr > 32)) {
- eisr1 = readl_relaxed(base + GICH_EISR1);
- elrsr1 = readl_relaxed(base + GICH_ELRSR1);
- } else {
- eisr1 = elrsr1 = 0;
- }
+
+ if (vcpu->arch.vgic_cpu.live_lrs) {
+ eisr0 = readl_relaxed(base + GICH_EISR0);
+ elrsr0 = readl_relaxed(base + GICH_ELRSR0);
+ cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
+ cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
+
+ if (unlikely(nr_lr > 32)) {
+ eisr1 = readl_relaxed(base + GICH_EISR1);
+ elrsr1 = readl_relaxed(base + GICH_ELRSR1);
+ } else {
+ eisr1 = elrsr1 = 0;
+ }
+
#ifdef CONFIG_CPU_BIG_ENDIAN
- cpu_if->vgic_eisr = ((u64)eisr0 << 32) | eisr1;
- cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
+ cpu_if->vgic_eisr = ((u64)eisr0 << 32) | eisr1;
+ cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
#else
- cpu_if->vgic_eisr = ((u64)eisr1 << 32) | eisr0;
- cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
+ cpu_if->vgic_eisr = ((u64)eisr1 << 32) | eisr0;
+ cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
#endif
- cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
- writel_relaxed(0, base + GICH_HCR);
+ for (i = 0; i < nr_lr; i++)
+ if (vcpu->arch.vgic_cpu.live_lrs & (1UL << i))
+ cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
- for (i = 0; i < nr_lr; i++)
- cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
+ writel_relaxed(0, base + GICH_HCR);
+
+ vcpu->arch.vgic_cpu.live_lrs = 0;
+ } else {
+ cpu_if->vgic_eisr = 0;
+ cpu_if->vgic_elrsr = ~0UL;
+ cpu_if->vgic_misr = 0;
+ cpu_if->vgic_apr = 0;
+ }
}
/* vcpu is already in the HYP VA space */
@@ -68,15 +81,30 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
struct vgic_dist *vgic = &kvm->arch.vgic;
void __iomem *base = kern_hyp_va(vgic->vctrl_base);
int i, nr_lr;
+ u64 live_lrs = 0;
if (!base)
return;
- writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
- writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
- writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
-
nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+
for (i = 0; i < nr_lr; i++)
- writel_relaxed(cpu_if->vgic_lr[i], base + GICH_LR0 + (i * 4));
+ if (cpu_if->vgic_lr[i] & GICH_LR_STATE)
+ live_lrs |= 1UL << i;
+
+ if (live_lrs) {
+ writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
+ writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
+ for (i = 0; i < nr_lr; i++) {
+ u32 val = 0;
+
+ if (live_lrs & (1UL << i))
+ val = cpu_if->vgic_lr[i];
+
+ writel_relaxed(val, base + GICH_LR0 + (i * 4));
+ }
+ }
+
+ writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
+ vcpu->arch.vgic_cpu.live_lrs = live_lrs;
}
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 02/12] KVM: arm/arm64: vgic-v2: Save maintenance interrupt state only if required
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 01/12] KVM: arm/arm64: vgic-v2: Avoid accessing GICH registers Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 03/12] KVM: arm/arm64: vgic-v2: Move GICH_ELRSR saving to its own function Marc Zyngier
` (9 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
Next on our list of useless accesses is the maintenance interrupt
status registers (GICH_MISR, GICH_EISR{0,1}).
It is pointless to save them if we haven't asked for a maintenance
interrupt the first place, which can only happen for two reasons:
- Underflow: GICH_HCR_UIE will be set,
- EOI: GICH_LR_EOI will be set.
These conditions can be checked on the in-memory copies of the regs.
Should any of these two condition be valid, we must read GICH_MISR.
We can then check for GICH_MISR_EOI, and only when set read
GICH_EISR*.
This means that in most case, we don't have to save them at all.
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
virt/kvm/arm/hyp/vgic-v2-sr.c | 54 +++++++++++++++++++++++++++++++++++++------
1 file changed, 47 insertions(+), 7 deletions(-)
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index aa0fdb8..0dd83d5 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -21,6 +21,49 @@
#include <asm/kvm_hyp.h>
+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;
+ u32 eisr0, eisr1;
+ int i;
+ bool expect_mi;
+
+ expect_mi = !!(cpu_if->vgic_hcr & GICH_HCR_UIE);
+
+ for (i = 0; i < nr_lr; i++) {
+ if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
+ continue;
+
+ expect_mi |= (!(cpu_if->vgic_lr[i] & GICH_LR_HW) &&
+ (cpu_if->vgic_lr[i] & GICH_LR_EOI));
+ }
+
+ if (expect_mi) {
+ cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
+
+ if (cpu_if->vgic_misr & GICH_MISR_EOI) {
+ eisr0 = readl_relaxed(base + GICH_EISR0);
+ if (unlikely(nr_lr > 32))
+ eisr1 = readl_relaxed(base + GICH_EISR1);
+ else
+ eisr1 = 0;
+ } else {
+ eisr0 = eisr1 = 0;
+ }
+ } else {
+ cpu_if->vgic_misr = 0;
+ eisr0 = eisr1 = 0;
+ }
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ cpu_if->vgic_eisr = ((u64)eisr0 << 32) | eisr1;
+#else
+ cpu_if->vgic_eisr = ((u64)eisr1 << 32) | eisr0;
+#endif
+}
+
/* vcpu is already in the HYP VA space */
void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
{
@@ -28,7 +71,7 @@ void __hyp_text __vgic_v2_save_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);
- u32 eisr0, eisr1, elrsr0, elrsr1;
+ u32 elrsr0, elrsr1;
int i, nr_lr;
if (!base)
@@ -38,26 +81,23 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
if (vcpu->arch.vgic_cpu.live_lrs) {
- eisr0 = readl_relaxed(base + GICH_EISR0);
elrsr0 = readl_relaxed(base + GICH_ELRSR0);
- cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
if (unlikely(nr_lr > 32)) {
- eisr1 = readl_relaxed(base + GICH_EISR1);
elrsr1 = readl_relaxed(base + GICH_ELRSR1);
} else {
- eisr1 = elrsr1 = 0;
+ elrsr1 = 0;
}
#ifdef CONFIG_CPU_BIG_ENDIAN
- cpu_if->vgic_eisr = ((u64)eisr0 << 32) | eisr1;
cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
#else
- cpu_if->vgic_eisr = ((u64)eisr1 << 32) | eisr0;
cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
#endif
+ save_maint_int_state(vcpu, base);
+
for (i = 0; i < nr_lr; i++)
if (vcpu->arch.vgic_cpu.live_lrs & (1UL << i))
cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 03/12] KVM: arm/arm64: vgic-v2: Move GICH_ELRSR saving to its own function
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 01/12] KVM: arm/arm64: vgic-v2: Avoid accessing GICH registers Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 02/12] KVM: arm/arm64: vgic-v2: Save maintenance interrupt state only if required Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 04/12] KVM: arm/arm64: vgic-v2: Do not save an LR known to be empty Marc Zyngier
` (8 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
In order to make the saving path slightly more readable and
prepare for some more optimizations, let's move the GICH_ELRSR
saving to its own function.
No functional change.
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
virt/kvm/arm/hyp/vgic-v2-sr.c | 36 +++++++++++++++++++++---------------
1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 0dd83d5..c576228 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -64,6 +64,25 @@ static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
#endif
}
+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;
+ u32 elrsr0, elrsr1;
+
+ elrsr0 = readl_relaxed(base + GICH_ELRSR0);
+ if (unlikely(nr_lr > 32))
+ elrsr1 = readl_relaxed(base + GICH_ELRSR1);
+ else
+ elrsr1 = 0;
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
+#else
+ cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
+#endif
+}
+
/* vcpu is already in the HYP VA space */
void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
{
@@ -71,7 +90,6 @@ void __hyp_text __vgic_v2_save_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);
- u32 elrsr0, elrsr1;
int i, nr_lr;
if (!base)
@@ -81,22 +99,10 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
if (vcpu->arch.vgic_cpu.live_lrs) {
- elrsr0 = readl_relaxed(base + GICH_ELRSR0);
- cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
-
- if (unlikely(nr_lr > 32)) {
- elrsr1 = readl_relaxed(base + GICH_ELRSR1);
- } else {
- elrsr1 = 0;
- }
-
-#ifdef CONFIG_CPU_BIG_ENDIAN
- cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
-#else
- cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
-#endif
+ cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
save_maint_int_state(vcpu, base);
+ save_elrsr(vcpu, base);
for (i = 0; i < nr_lr; i++)
if (vcpu->arch.vgic_cpu.live_lrs & (1UL << i))
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 04/12] KVM: arm/arm64: vgic-v2: Do not save an LR known to be empty
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
` (2 preceding siblings ...)
2016-03-07 9:33 ` [PATCH v3 03/12] KVM: arm/arm64: vgic-v2: Move GICH_ELRSR saving to its own function Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 05/12] KVM: arm/arm64: vgic-v2: Reset LRs at boot time Marc Zyngier
` (7 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
On exit, any empty LR will be signaled in GICH_ELRSR*. Which
means that we do not have to save it, and we can just clear
its state in the in-memory copy.
Take this opportunity to move the LR saving code into its
own function.
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
virt/kvm/arm/hyp/vgic-v2-sr.c | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index c576228..6d4dd78 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -83,6 +83,25 @@ static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
#endif
}
+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 i;
+
+ for (i = 0; i < nr_lr; i++) {
+ if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
+ continue;
+
+ if (cpu_if->vgic_elrsr & (1UL << i)) {
+ cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
+ continue;
+ }
+
+ cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
+ }
+}
+
/* vcpu is already in the HYP VA space */
void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
{
@@ -90,12 +109,10 @@ void __hyp_text __vgic_v2_save_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;
if (!base)
return;
- nr_lr = vcpu->arch.vgic_cpu.nr_lr;
cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
if (vcpu->arch.vgic_cpu.live_lrs) {
@@ -103,10 +120,7 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
save_maint_int_state(vcpu, base);
save_elrsr(vcpu, base);
-
- for (i = 0; i < nr_lr; i++)
- if (vcpu->arch.vgic_cpu.live_lrs & (1UL << i))
- cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
+ save_lrs(vcpu, base);
writel_relaxed(0, base + GICH_HCR);
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 05/12] KVM: arm/arm64: vgic-v2: Reset LRs at boot time
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
` (3 preceding siblings ...)
2016-03-07 9:33 ` [PATCH v3 04/12] KVM: arm/arm64: vgic-v2: Do not save an LR known to be empty Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
2016-03-09 3:07 ` Christoffer Dall
2016-03-07 9:33 ` [PATCH v3 06/12] KVM: arm/arm64: vgic-v2: Only wipe LRs on vcpu exit Marc Zyngier
` (6 subsequent siblings)
11 siblings, 1 reply; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
In order to let make the GICv2 code more lazy in the way it
accesses the LRs, it is necessary to start with a clean slate.
Let's reset the LRs on each CPU when the vgic is probed.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
virt/kvm/arm/vgic-v2.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c
index ff02f08..67ec334 100644
--- a/virt/kvm/arm/vgic-v2.c
+++ b/virt/kvm/arm/vgic-v2.c
@@ -176,6 +176,15 @@ static const struct vgic_ops vgic_v2_ops = {
static struct vgic_params vgic_v2_params;
+static void vgic_cpu_init_lrs(void *params)
+{
+ struct vgic_params *vgic = params;
+ int i;
+
+ for (i = 0; i < vgic->nr_lr; i++)
+ writel_relaxed(0, vgic->vctrl_base + GICH_LR0 + (i * 4));
+}
+
/**
* vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
* @node: pointer to the DT node
@@ -257,6 +266,9 @@ int vgic_v2_probe(struct device_node *vgic_node,
vgic->type = VGIC_V2;
vgic->max_gic_vcpus = VGIC_V2_MAX_CPUS;
+
+ on_each_cpu(vgic_cpu_init_lrs, vgic, 1);
+
*ops = &vgic_v2_ops;
*params = vgic;
goto out;
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 06/12] KVM: arm/arm64: vgic-v2: Only wipe LRs on vcpu exit
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
` (4 preceding siblings ...)
2016-03-07 9:33 ` [PATCH v3 05/12] KVM: arm/arm64: vgic-v2: Reset LRs at boot time Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
2016-03-09 3:09 ` Christoffer Dall
2016-03-07 9:33 ` [PATCH v3 07/12] KVM: arm/arm64: vgic-v2: Make GICD_SGIR quicker to hit Marc Zyngier
` (5 subsequent siblings)
11 siblings, 1 reply; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
So far, we're always writing all possible LRs, setting the empty
ones with a zero value. This is obvious doing a lot of work for
nothing, and we're better off clearing those we've actually
dirtied on the exit path (it is very rare to inject more than one
interrupt at a time anyway).
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
virt/kvm/arm/hyp/vgic-v2-sr.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 6d4dd78..674bdf8 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -99,6 +99,7 @@ static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
}
cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
+ writel_relaxed(0, base + GICH_LR0 + (i * 4));
}
}
@@ -156,12 +157,11 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
for (i = 0; i < nr_lr; i++) {
- u32 val = 0;
-
- if (live_lrs & (1UL << i))
- val = cpu_if->vgic_lr[i];
+ if (!(live_lrs & (1UL << i)))
+ continue;
- writel_relaxed(val, base + GICH_LR0 + (i * 4));
+ writel_relaxed(cpu_if->vgic_lr[i],
+ base + GICH_LR0 + (i * 4));
}
}
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 07/12] KVM: arm/arm64: vgic-v2: Make GICD_SGIR quicker to hit
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
` (5 preceding siblings ...)
2016-03-07 9:33 ` [PATCH v3 06/12] KVM: arm/arm64: vgic-v2: Only wipe LRs on vcpu exit Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 08/12] arm64: KVM: vgic-v3: Avoid accessing ICH registers Marc Zyngier
` (4 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
The GICD_SGIR register lives a long way from the beginning of
the handler array, which is searched linearly. As this is hit
pretty often, let's move it up. This saves us some precious
cycles when the guest is generating IPIs.
Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
virt/kvm/arm/vgic-v2-emul.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c
index 1390797..1b0bee0 100644
--- a/virt/kvm/arm/vgic-v2-emul.c
+++ b/virt/kvm/arm/vgic-v2-emul.c
@@ -321,6 +321,11 @@ static bool handle_mmio_sgi_clear(struct kvm_vcpu *vcpu,
static const struct vgic_io_range vgic_dist_ranges[] = {
{
+ .base = GIC_DIST_SOFTINT,
+ .len = 4,
+ .handle_mmio = handle_mmio_sgi_reg,
+ },
+ {
.base = GIC_DIST_CTRL,
.len = 12,
.bits_per_irq = 0,
@@ -387,11 +392,6 @@ static const struct vgic_io_range vgic_dist_ranges[] = {
.handle_mmio = handle_mmio_cfg_reg,
},
{
- .base = GIC_DIST_SOFTINT,
- .len = 4,
- .handle_mmio = handle_mmio_sgi_reg,
- },
- {
.base = GIC_DIST_SGI_PENDING_CLEAR,
.len = VGIC_NR_SGIS,
.handle_mmio = handle_mmio_sgi_clear,
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 08/12] arm64: KVM: vgic-v3: Avoid accessing ICH registers
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
` (6 preceding siblings ...)
2016-03-07 9:33 ` [PATCH v3 07/12] KVM: arm/arm64: vgic-v2: Make GICD_SGIR quicker to hit Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 09/12] arm64: KVM: vgic-v3: Save maintenance interrupt state only if required Marc Zyngier
` (3 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
Just like on GICv2, we're a bit hammer-happy with GICv3, and access
them more often than we should.
Adopt a policy similar to what we do for GICv2, only save/restoring
the minimal set of registers. As we don't access the registers
linearly anymore (we may skip some), the convoluted accessors become
slightly simpler, and we can drop the ugly indexing macro that
tended to confuse the reviewers.
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/kvm/hyp/vgic-v3-sr.c | 293 ++++++++++++++++++++++++----------------
include/kvm/arm_vgic.h | 6 -
virt/kvm/arm/vgic-v3.c | 4 +-
3 files changed, 182 insertions(+), 121 deletions(-)
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index 0035b2d..e596945 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -37,12 +37,104 @@
asm volatile("msr_s " __stringify(r) ", %0" : : "r" (__val));\
} while (0)
-/* vcpu is already in the HYP VA space */
+static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
+{
+ switch (lr & 0xf) {
+ case 0:
+ return read_gicreg(ICH_LR0_EL2);
+ case 1:
+ return read_gicreg(ICH_LR1_EL2);
+ case 2:
+ return read_gicreg(ICH_LR2_EL2);
+ case 3:
+ return read_gicreg(ICH_LR3_EL2);
+ case 4:
+ return read_gicreg(ICH_LR4_EL2);
+ case 5:
+ return read_gicreg(ICH_LR5_EL2);
+ case 6:
+ return read_gicreg(ICH_LR6_EL2);
+ case 7:
+ return read_gicreg(ICH_LR7_EL2);
+ case 8:
+ return read_gicreg(ICH_LR8_EL2);
+ case 9:
+ return read_gicreg(ICH_LR9_EL2);
+ case 10:
+ return read_gicreg(ICH_LR10_EL2);
+ case 11:
+ return read_gicreg(ICH_LR11_EL2);
+ case 12:
+ return read_gicreg(ICH_LR12_EL2);
+ case 13:
+ return read_gicreg(ICH_LR13_EL2);
+ case 14:
+ return read_gicreg(ICH_LR14_EL2);
+ case 15:
+ return read_gicreg(ICH_LR15_EL2);
+ }
+
+ unreachable();
+}
+
+static void __hyp_text __gic_v3_set_lr(u64 val, int lr)
+{
+ switch (lr & 0xf) {
+ case 0:
+ write_gicreg(val, ICH_LR0_EL2);
+ break;
+ case 1:
+ write_gicreg(val, ICH_LR1_EL2);
+ break;
+ case 2:
+ write_gicreg(val, ICH_LR2_EL2);
+ break;
+ case 3:
+ write_gicreg(val, ICH_LR3_EL2);
+ break;
+ case 4:
+ write_gicreg(val, ICH_LR4_EL2);
+ break;
+ case 5:
+ write_gicreg(val, ICH_LR5_EL2);
+ break;
+ case 6:
+ write_gicreg(val, ICH_LR6_EL2);
+ break;
+ case 7:
+ write_gicreg(val, ICH_LR7_EL2);
+ break;
+ case 8:
+ write_gicreg(val, ICH_LR8_EL2);
+ break;
+ case 9:
+ write_gicreg(val, ICH_LR9_EL2);
+ break;
+ case 10:
+ write_gicreg(val, ICH_LR10_EL2);
+ break;
+ case 11:
+ write_gicreg(val, ICH_LR11_EL2);
+ break;
+ case 12:
+ write_gicreg(val, ICH_LR12_EL2);
+ break;
+ case 13:
+ write_gicreg(val, ICH_LR13_EL2);
+ break;
+ case 14:
+ write_gicreg(val, ICH_LR14_EL2);
+ break;
+ case 15:
+ write_gicreg(val, ICH_LR15_EL2);
+ break;
+ }
+}
+
void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
{
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
u64 val;
- u32 max_lr_idx, nr_pri_bits;
/*
* Make sure stores to the GIC via the memory mapped interface
@@ -51,68 +143,58 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
dsb(st);
cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
- cpu_if->vgic_misr = read_gicreg(ICH_MISR_EL2);
- cpu_if->vgic_eisr = read_gicreg(ICH_EISR_EL2);
- cpu_if->vgic_elrsr = read_gicreg(ICH_ELSR_EL2);
- write_gicreg(0, ICH_HCR_EL2);
- val = read_gicreg(ICH_VTR_EL2);
- max_lr_idx = vtr_to_max_lr_idx(val);
- nr_pri_bits = vtr_to_nr_pri_bits(val);
+ if (vcpu->arch.vgic_cpu.live_lrs) {
+ int i;
+ u32 max_lr_idx, nr_pri_bits;
- switch (max_lr_idx) {
- case 15:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(15)] = read_gicreg(ICH_LR15_EL2);
- case 14:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(14)] = read_gicreg(ICH_LR14_EL2);
- case 13:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(13)] = read_gicreg(ICH_LR13_EL2);
- case 12:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(12)] = read_gicreg(ICH_LR12_EL2);
- case 11:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(11)] = read_gicreg(ICH_LR11_EL2);
- case 10:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(10)] = read_gicreg(ICH_LR10_EL2);
- case 9:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(9)] = read_gicreg(ICH_LR9_EL2);
- case 8:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(8)] = read_gicreg(ICH_LR8_EL2);
- case 7:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(7)] = read_gicreg(ICH_LR7_EL2);
- case 6:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(6)] = read_gicreg(ICH_LR6_EL2);
- case 5:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(5)] = read_gicreg(ICH_LR5_EL2);
- case 4:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(4)] = read_gicreg(ICH_LR4_EL2);
- case 3:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(3)] = read_gicreg(ICH_LR3_EL2);
- case 2:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(2)] = read_gicreg(ICH_LR2_EL2);
- case 1:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(1)] = read_gicreg(ICH_LR1_EL2);
- case 0:
- cpu_if->vgic_lr[VGIC_V3_LR_INDEX(0)] = read_gicreg(ICH_LR0_EL2);
- }
+ cpu_if->vgic_misr = read_gicreg(ICH_MISR_EL2);
+ cpu_if->vgic_eisr = read_gicreg(ICH_EISR_EL2);
+ cpu_if->vgic_elrsr = read_gicreg(ICH_ELSR_EL2);
- switch (nr_pri_bits) {
- case 7:
- cpu_if->vgic_ap0r[3] = read_gicreg(ICH_AP0R3_EL2);
- cpu_if->vgic_ap0r[2] = read_gicreg(ICH_AP0R2_EL2);
- case 6:
- cpu_if->vgic_ap0r[1] = read_gicreg(ICH_AP0R1_EL2);
- default:
- cpu_if->vgic_ap0r[0] = read_gicreg(ICH_AP0R0_EL2);
- }
+ write_gicreg(0, ICH_HCR_EL2);
+ val = read_gicreg(ICH_VTR_EL2);
+ max_lr_idx = vtr_to_max_lr_idx(val);
+ nr_pri_bits = vtr_to_nr_pri_bits(val);
- switch (nr_pri_bits) {
- case 7:
- cpu_if->vgic_ap1r[3] = read_gicreg(ICH_AP1R3_EL2);
- cpu_if->vgic_ap1r[2] = read_gicreg(ICH_AP1R2_EL2);
- case 6:
- cpu_if->vgic_ap1r[1] = read_gicreg(ICH_AP1R1_EL2);
- default:
- cpu_if->vgic_ap1r[0] = read_gicreg(ICH_AP1R0_EL2);
+ for (i = 0; i <= max_lr_idx; i++) {
+ if (vcpu->arch.vgic_cpu.live_lrs & (1UL << i))
+ cpu_if->vgic_lr[i] = __gic_v3_get_lr(i);
+ }
+
+ switch (nr_pri_bits) {
+ case 7:
+ cpu_if->vgic_ap0r[3] = read_gicreg(ICH_AP0R3_EL2);
+ cpu_if->vgic_ap0r[2] = read_gicreg(ICH_AP0R2_EL2);
+ case 6:
+ cpu_if->vgic_ap0r[1] = read_gicreg(ICH_AP0R1_EL2);
+ default:
+ cpu_if->vgic_ap0r[0] = read_gicreg(ICH_AP0R0_EL2);
+ }
+
+ switch (nr_pri_bits) {
+ case 7:
+ cpu_if->vgic_ap1r[3] = read_gicreg(ICH_AP1R3_EL2);
+ cpu_if->vgic_ap1r[2] = read_gicreg(ICH_AP1R2_EL2);
+ case 6:
+ cpu_if->vgic_ap1r[1] = read_gicreg(ICH_AP1R1_EL2);
+ default:
+ cpu_if->vgic_ap1r[0] = read_gicreg(ICH_AP1R0_EL2);
+ }
+
+ vcpu->arch.vgic_cpu.live_lrs = 0;
+ } else {
+ cpu_if->vgic_misr = 0;
+ cpu_if->vgic_eisr = 0;
+ cpu_if->vgic_elrsr = 0xffff;
+ cpu_if->vgic_ap0r[0] = 0;
+ cpu_if->vgic_ap0r[1] = 0;
+ cpu_if->vgic_ap0r[2] = 0;
+ cpu_if->vgic_ap0r[3] = 0;
+ cpu_if->vgic_ap1r[0] = 0;
+ cpu_if->vgic_ap1r[1] = 0;
+ cpu_if->vgic_ap1r[2] = 0;
+ cpu_if->vgic_ap1r[3] = 0;
}
val = read_gicreg(ICC_SRE_EL2);
@@ -126,6 +208,8 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
u64 val;
u32 max_lr_idx, nr_pri_bits;
+ u16 live_lrs = 0;
+ int i;
/*
* VFIQEn is RES1 if ICC_SRE_EL1.SRE is 1. This causes a
@@ -138,66 +222,48 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
write_gicreg(cpu_if->vgic_sre, ICC_SRE_EL1);
isb();
- write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
- write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
-
val = read_gicreg(ICH_VTR_EL2);
max_lr_idx = vtr_to_max_lr_idx(val);
nr_pri_bits = vtr_to_nr_pri_bits(val);
- switch (nr_pri_bits) {
- case 7:
- write_gicreg(cpu_if->vgic_ap0r[3], ICH_AP0R3_EL2);
- write_gicreg(cpu_if->vgic_ap0r[2], ICH_AP0R2_EL2);
- case 6:
- write_gicreg(cpu_if->vgic_ap0r[1], ICH_AP0R1_EL2);
- default:
- write_gicreg(cpu_if->vgic_ap0r[0], ICH_AP0R0_EL2);
+ for (i = 0; i <= max_lr_idx; i++) {
+ if (cpu_if->vgic_lr[i] & ICH_LR_STATE)
+ live_lrs |= (1 << i);
}
- switch (nr_pri_bits) {
- case 7:
- write_gicreg(cpu_if->vgic_ap1r[3], ICH_AP1R3_EL2);
- write_gicreg(cpu_if->vgic_ap1r[2], ICH_AP1R2_EL2);
- case 6:
- write_gicreg(cpu_if->vgic_ap1r[1], ICH_AP1R1_EL2);
- default:
- write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
- }
+ write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
- switch (max_lr_idx) {
- case 15:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(15)], ICH_LR15_EL2);
- case 14:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(14)], ICH_LR14_EL2);
- case 13:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(13)], ICH_LR13_EL2);
- case 12:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(12)], ICH_LR12_EL2);
- case 11:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(11)], ICH_LR11_EL2);
- case 10:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(10)], ICH_LR10_EL2);
- case 9:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(9)], ICH_LR9_EL2);
- case 8:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(8)], ICH_LR8_EL2);
- case 7:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(7)], ICH_LR7_EL2);
- case 6:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(6)], ICH_LR6_EL2);
- case 5:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(5)], ICH_LR5_EL2);
- case 4:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(4)], ICH_LR4_EL2);
- case 3:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(3)], ICH_LR3_EL2);
- case 2:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(2)], ICH_LR2_EL2);
- case 1:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(1)], ICH_LR1_EL2);
- case 0:
- write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(0)], ICH_LR0_EL2);
+ if (live_lrs) {
+ write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
+
+ switch (nr_pri_bits) {
+ case 7:
+ write_gicreg(cpu_if->vgic_ap0r[3], ICH_AP0R3_EL2);
+ write_gicreg(cpu_if->vgic_ap0r[2], ICH_AP0R2_EL2);
+ case 6:
+ write_gicreg(cpu_if->vgic_ap0r[1], ICH_AP0R1_EL2);
+ default:
+ write_gicreg(cpu_if->vgic_ap0r[0], ICH_AP0R0_EL2);
+ }
+
+ switch (nr_pri_bits) {
+ case 7:
+ write_gicreg(cpu_if->vgic_ap1r[3], ICH_AP1R3_EL2);
+ write_gicreg(cpu_if->vgic_ap1r[2], ICH_AP1R2_EL2);
+ case 6:
+ write_gicreg(cpu_if->vgic_ap1r[1], ICH_AP1R1_EL2);
+ default:
+ write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
+ }
+
+ for (i = 0; i <= max_lr_idx; i++) {
+ val = 0;
+
+ if (live_lrs & (1 << i))
+ val = cpu_if->vgic_lr[i];
+
+ __gic_v3_set_lr(val, i);
+ }
}
/*
@@ -207,6 +273,7 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
*/
isb();
dsb(sy);
+ vcpu->arch.vgic_cpu.live_lrs = live_lrs;
/*
* Prevent the guest from touching the GIC system registers if
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index f473fd6..281caf8 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -279,12 +279,6 @@ struct vgic_v2_cpu_if {
u32 vgic_lr[VGIC_V2_MAX_LRS];
};
-/*
- * LRs are stored in reverse order in memory. make sure we index them
- * correctly.
- */
-#define VGIC_V3_LR_INDEX(lr) (VGIC_V3_MAX_LRS - 1 - lr)
-
struct vgic_v3_cpu_if {
#ifdef CONFIG_KVM_ARM_VGIC_V3
u32 vgic_hcr;
diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
index 453eafd..11b5ff6 100644
--- a/virt/kvm/arm/vgic-v3.c
+++ b/virt/kvm/arm/vgic-v3.c
@@ -42,7 +42,7 @@ static u32 ich_vtr_el2;
static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
{
struct vgic_lr lr_desc;
- u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[VGIC_V3_LR_INDEX(lr)];
+ u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr];
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
lr_desc.irq = val & ICH_LR_VIRTUALID_MASK;
@@ -106,7 +106,7 @@ static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr,
lr_val |= ((u64)lr_desc.hwirq) << ICH_LR_PHYS_ID_SHIFT;
}
- vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[VGIC_V3_LR_INDEX(lr)] = lr_val;
+ vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = lr_val;
if (!(lr_desc.state & LR_STATE_MASK))
vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 09/12] arm64: KVM: vgic-v3: Save maintenance interrupt state only if required
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
` (7 preceding siblings ...)
2016-03-07 9:33 ` [PATCH v3 08/12] arm64: KVM: vgic-v3: Avoid accessing ICH registers Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 10/12] arm64: KVM: vgic-v3: Do not save an LR known to be empty Marc Zyngier
` (2 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
Next on our list of useless accesses is the maintenance interrupt
status registers (ICH_MISR_EL2, ICH_EISR_EL2).
It is pointless to save them if we haven't asked for a maintenance
interrupt the first place, which can only happen for two reasons:
- Underflow: ICH_HCR_UIE will be set,
- EOI: ICH_LR_EOI will be set.
These conditions can be checked on the in-memory copies of the regs.
Should any of these two condition be valid, we must read GICH_MISR.
We can then check for ICH_MISR_EOI, and only when set read
ICH_EISR_EL2.
This means that in most case, we don't have to save them at all.
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/kvm/hyp/vgic-v3-sr.c | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index e596945..61a5e46 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -131,6 +131,35 @@ static void __hyp_text __gic_v3_set_lr(u64 val, int lr)
}
}
+static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu, int nr_lr)
+{
+ struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+ int i;
+ bool expect_mi;
+
+ expect_mi = !!(cpu_if->vgic_hcr & ICH_HCR_UIE);
+
+ for (i = 0; i < nr_lr; i++) {
+ if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
+ continue;
+
+ expect_mi |= (!(cpu_if->vgic_lr[i] & ICH_LR_HW) &&
+ (cpu_if->vgic_lr[i] & ICH_LR_EOI));
+ }
+
+ if (expect_mi) {
+ cpu_if->vgic_misr = read_gicreg(ICH_MISR_EL2);
+
+ if (cpu_if->vgic_misr & ICH_MISR_EOI)
+ cpu_if->vgic_eisr = read_gicreg(ICH_EISR_EL2);
+ else
+ cpu_if->vgic_eisr = 0;
+ } else {
+ cpu_if->vgic_misr = 0;
+ cpu_if->vgic_eisr = 0;
+ }
+}
+
void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
{
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -148,8 +177,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
int i;
u32 max_lr_idx, nr_pri_bits;
- cpu_if->vgic_misr = read_gicreg(ICH_MISR_EL2);
- cpu_if->vgic_eisr = read_gicreg(ICH_EISR_EL2);
cpu_if->vgic_elrsr = read_gicreg(ICH_ELSR_EL2);
write_gicreg(0, ICH_HCR_EL2);
@@ -157,6 +184,8 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
max_lr_idx = vtr_to_max_lr_idx(val);
nr_pri_bits = vtr_to_nr_pri_bits(val);
+ save_maint_int_state(vcpu, max_lr_idx + 1);
+
for (i = 0; i <= max_lr_idx; i++) {
if (vcpu->arch.vgic_cpu.live_lrs & (1UL << i))
cpu_if->vgic_lr[i] = __gic_v3_get_lr(i);
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 10/12] arm64: KVM: vgic-v3: Do not save an LR known to be empty
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
` (8 preceding siblings ...)
2016-03-07 9:33 ` [PATCH v3 09/12] arm64: KVM: vgic-v3: Save maintenance interrupt state only if required Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 11/12] arm64: KVM: vgic-v3: Reset LRs at boot time Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 12/12] arm64: KVM: vgic-v3: Only wipe LRs on vcpu exit Marc Zyngier
11 siblings, 0 replies; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
On exit, any empty LR will be signaled in ICH_ELRSR_EL2. Which
means that we do not have to save it, and we can just clear
its state in the in-memory copy.
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/kvm/hyp/vgic-v3-sr.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index 61a5e46..0db426e 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -187,8 +187,15 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
save_maint_int_state(vcpu, max_lr_idx + 1);
for (i = 0; i <= max_lr_idx; i++) {
- if (vcpu->arch.vgic_cpu.live_lrs & (1UL << i))
- cpu_if->vgic_lr[i] = __gic_v3_get_lr(i);
+ if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
+ continue;
+
+ if (cpu_if->vgic_elrsr & (1 << i)) {
+ cpu_if->vgic_lr[i] &= ~ICH_LR_STATE;
+ continue;
+ }
+
+ cpu_if->vgic_lr[i] = __gic_v3_get_lr(i);
}
switch (nr_pri_bits) {
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 11/12] arm64: KVM: vgic-v3: Reset LRs at boot time
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
` (9 preceding siblings ...)
2016-03-07 9:33 ` [PATCH v3 10/12] arm64: KVM: vgic-v3: Do not save an LR known to be empty Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
2016-03-09 3:12 ` Christoffer Dall
2016-03-07 9:33 ` [PATCH v3 12/12] arm64: KVM: vgic-v3: Only wipe LRs on vcpu exit Marc Zyngier
11 siblings, 1 reply; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
In order to let the GICv3 code be more lazy in the way it
accesses the LRs, it is necessary to start with a clean slate.
Let's reset the LRs on each CPU when the vgic is probed (which
includes a round trip to EL2...).
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/include/asm/kvm_asm.h | 1 +
arch/arm64/kvm/hyp/vgic-v3-sr.c | 9 +++++++++
virt/kvm/arm/vgic-v3.c | 7 +++++++
3 files changed, 17 insertions(+)
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 1037392..2d02ba6 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -42,6 +42,7 @@ extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
extern u64 __vgic_v3_get_ich_vtr_el2(void);
+extern void __vgic_v3_init_lrs(void);
extern u32 __kvm_get_mdcr_el2(void);
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index 0db426e..8134947 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -321,6 +321,15 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
}
}
+void __hyp_text __vgic_v3_init_lrs(void)
+{
+ int max_lr_idx = vtr_to_max_lr_idx(read_gicreg(ICH_VTR_EL2));
+ int i;
+
+ for (i = 0; i <= max_lr_idx; i++)
+ __gic_v3_set_lr(0, i);
+}
+
static u64 __hyp_text __vgic_v3_read_ich_vtr_el2(void)
{
return read_gicreg(ICH_VTR_EL2);
diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
index 11b5ff6..999bdc6 100644
--- a/virt/kvm/arm/vgic-v3.c
+++ b/virt/kvm/arm/vgic-v3.c
@@ -216,6 +216,11 @@ static const struct vgic_ops vgic_v3_ops = {
static struct vgic_params vgic_v3_params;
+static void vgic_cpu_init_lrs(void *params)
+{
+ kvm_call_hyp(__vgic_v3_init_lrs);
+}
+
/**
* vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
* @node: pointer to the DT node
@@ -284,6 +289,8 @@ int vgic_v3_probe(struct device_node *vgic_node,
kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
vcpu_res.start, vgic->maint_irq);
+ on_each_cpu(vgic_cpu_init_lrs, vgic, 1);
+
*ops = &vgic_v3_ops;
*params = vgic;
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 12/12] arm64: KVM: vgic-v3: Only wipe LRs on vcpu exit
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
` (10 preceding siblings ...)
2016-03-07 9:33 ` [PATCH v3 11/12] arm64: KVM: vgic-v3: Reset LRs at boot time Marc Zyngier
@ 2016-03-07 9:33 ` Marc Zyngier
11 siblings, 0 replies; 16+ messages in thread
From: Marc Zyngier @ 2016-03-07 9:33 UTC (permalink / raw)
To: linux-arm-kernel
So far, we're always writing all possible LRs, setting the empty
ones with a zero value. This is obvious doing a low of work for
nothing, and we're better off clearing those we've actually
dirtied on the exit path (it is very rare to inject more than one
interrupt at a time anyway).
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/kvm/hyp/vgic-v3-sr.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index 8134947..fff7cd4 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -196,6 +196,7 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
}
cpu_if->vgic_lr[i] = __gic_v3_get_lr(i);
+ __gic_v3_set_lr(0, i);
}
switch (nr_pri_bits) {
@@ -293,12 +294,10 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
}
for (i = 0; i <= max_lr_idx; i++) {
- val = 0;
-
- if (live_lrs & (1 << i))
- val = cpu_if->vgic_lr[i];
+ if (!(live_lrs & (1 << i)))
+ continue;
- __gic_v3_set_lr(val, i);
+ __gic_v3_set_lr(cpu_if->vgic_lr[i], i);
}
}
--
2.1.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 05/12] KVM: arm/arm64: vgic-v2: Reset LRs at boot time
2016-03-07 9:33 ` [PATCH v3 05/12] KVM: arm/arm64: vgic-v2: Reset LRs at boot time Marc Zyngier
@ 2016-03-09 3:07 ` Christoffer Dall
0 siblings, 0 replies; 16+ messages in thread
From: Christoffer Dall @ 2016-03-09 3:07 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Mar 07, 2016 at 09:33:27AM +0000, Marc Zyngier wrote:
> In order to let make the GICv2 code more lazy in the way it
> accesses the LRs, it is necessary to start with a clean slate.
>
> Let's reset the LRs on each CPU when the vgic is probed.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> virt/kvm/arm/vgic-v2.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c
> index ff02f08..67ec334 100644
> --- a/virt/kvm/arm/vgic-v2.c
> +++ b/virt/kvm/arm/vgic-v2.c
> @@ -176,6 +176,15 @@ static const struct vgic_ops vgic_v2_ops = {
>
> static struct vgic_params vgic_v2_params;
>
> +static void vgic_cpu_init_lrs(void *params)
> +{
> + struct vgic_params *vgic = params;
> + int i;
> +
> + for (i = 0; i < vgic->nr_lr; i++)
> + writel_relaxed(0, vgic->vctrl_base + GICH_LR0 + (i * 4));
> +}
> +
> /**
> * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
> * @node: pointer to the DT node
> @@ -257,6 +266,9 @@ int vgic_v2_probe(struct device_node *vgic_node,
>
> vgic->type = VGIC_V2;
> vgic->max_gic_vcpus = VGIC_V2_MAX_CPUS;
> +
> + on_each_cpu(vgic_cpu_init_lrs, vgic, 1);
> +
> *ops = &vgic_v2_ops;
> *params = vgic;
> goto out;
> --
> 2.1.4
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 06/12] KVM: arm/arm64: vgic-v2: Only wipe LRs on vcpu exit
2016-03-07 9:33 ` [PATCH v3 06/12] KVM: arm/arm64: vgic-v2: Only wipe LRs on vcpu exit Marc Zyngier
@ 2016-03-09 3:09 ` Christoffer Dall
0 siblings, 0 replies; 16+ messages in thread
From: Christoffer Dall @ 2016-03-09 3:09 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Mar 07, 2016 at 09:33:28AM +0000, Marc Zyngier wrote:
> So far, we're always writing all possible LRs, setting the empty
> ones with a zero value. This is obvious doing a lot of work for
> nothing, and we're better off clearing those we've actually
> dirtied on the exit path (it is very rare to inject more than one
> interrupt at a time anyway).
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> virt/kvm/arm/hyp/vgic-v2-sr.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
> index 6d4dd78..674bdf8 100644
> --- a/virt/kvm/arm/hyp/vgic-v2-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
> @@ -99,6 +99,7 @@ static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
> }
>
> cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
> + writel_relaxed(0, base + GICH_LR0 + (i * 4));
> }
> }
>
> @@ -156,12 +157,11 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
> writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
> writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
> for (i = 0; i < nr_lr; i++) {
> - u32 val = 0;
> -
> - if (live_lrs & (1UL << i))
> - val = cpu_if->vgic_lr[i];
> + if (!(live_lrs & (1UL << i)))
> + continue;
>
> - writel_relaxed(val, base + GICH_LR0 + (i * 4));
> + writel_relaxed(cpu_if->vgic_lr[i],
> + base + GICH_LR0 + (i * 4));
> }
> }
>
> --
> 2.1.4
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 11/12] arm64: KVM: vgic-v3: Reset LRs at boot time
2016-03-07 9:33 ` [PATCH v3 11/12] arm64: KVM: vgic-v3: Reset LRs at boot time Marc Zyngier
@ 2016-03-09 3:12 ` Christoffer Dall
0 siblings, 0 replies; 16+ messages in thread
From: Christoffer Dall @ 2016-03-09 3:12 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Mar 07, 2016 at 09:33:33AM +0000, Marc Zyngier wrote:
> In order to let the GICv3 code be more lazy in the way it
> accesses the LRs, it is necessary to start with a clean slate.
>
> Let's reset the LRs on each CPU when the vgic is probed (which
> includes a round trip to EL2...).
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2016-03-09 3:12 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-03-07 9:33 [PATCH v3 00/12] Virtual GIC save/restore optimization Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 01/12] KVM: arm/arm64: vgic-v2: Avoid accessing GICH registers Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 02/12] KVM: arm/arm64: vgic-v2: Save maintenance interrupt state only if required Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 03/12] KVM: arm/arm64: vgic-v2: Move GICH_ELRSR saving to its own function Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 04/12] KVM: arm/arm64: vgic-v2: Do not save an LR known to be empty Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 05/12] KVM: arm/arm64: vgic-v2: Reset LRs at boot time Marc Zyngier
2016-03-09 3:07 ` Christoffer Dall
2016-03-07 9:33 ` [PATCH v3 06/12] KVM: arm/arm64: vgic-v2: Only wipe LRs on vcpu exit Marc Zyngier
2016-03-09 3:09 ` Christoffer Dall
2016-03-07 9:33 ` [PATCH v3 07/12] KVM: arm/arm64: vgic-v2: Make GICD_SGIR quicker to hit Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 08/12] arm64: KVM: vgic-v3: Avoid accessing ICH registers Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 09/12] arm64: KVM: vgic-v3: Save maintenance interrupt state only if required Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 10/12] arm64: KVM: vgic-v3: Do not save an LR known to be empty Marc Zyngier
2016-03-07 9:33 ` [PATCH v3 11/12] arm64: KVM: vgic-v3: Reset LRs at boot time Marc Zyngier
2016-03-09 3:12 ` Christoffer Dall
2016-03-07 9:33 ` [PATCH v3 12/12] arm64: KVM: vgic-v3: Only wipe LRs on vcpu exit Marc Zyngier
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).