All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] KVM: arm/arm64: vgic: Improvements and optimizations
@ 2017-03-20 10:58 ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Marc Zyngier, Andre Przywara, Christoffer Dall, kvm

We can improve the performance of our VGIC implementation a bit and
clean up a lot of the implementation while we're at it.

At first, patch 1 may seem excessive for a single register, the VMCR,
but whlie it adds complexity it does move logic out of the critical path
and into the vcpu_load/put hooks, which are executed much more rarely.
It also provides an infrastructure to move more things into the
vgic_load/put functions later one.

Avoiding the need to take a spinlock in the common case where there are
no virtual interrupts in flight are actually measurable and well worth
the effort.

The implementation cleanups boil down to maintaining a single count of
the used lrs instead of an additional bitmap, avoiding the need to deel
with the MISR and EISR fields, and doing an early init of the VGIC to
avoid a number of vgic_initialized() checks.

Tested on Mustang and TC2, and Thunder-X.

Patches also available on:
git://git.kernel.org/pub/scm/linux/kernel/git/cdall/linux.git gic-optimize

Thanks,
-Christoffer

Christoffer Dall (8):
  KVM: arm/arm64: vgic: Defer touching GICH_VMCR to vcpu_load/put
  KVM: arm/arm64: vgic: Get rid of live_lrs
  KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance
    operation
  KVM: arm/arm64: vgic: Get rid of unnecessary save_maint_int_state
  KVM: arm/arm64: vgic: Get rid of MISR and EISR fields
  KVM: arm/arm64: vgic: Implement early VGIC init functionality
  KVM: arm/arm64: vgic: Don't check vgic_initialized in flush_hwstate
  KVM: arm/arm64: vgic: Improve sync_hwstate performance

Shih-Wei Li (1):
  KVM: arm/arm64: vgic: Avoid flushing vgic state when there's no
    pending IRQ

 arch/arm/include/asm/kvm_asm.h   |   3 ++
 arch/arm/kvm/arm.c               |  11 ++--
 arch/arm64/include/asm/kvm_asm.h |   2 +
 include/kvm/arm_vgic.h           |   9 ++--
 virt/kvm/arm/hyp/vgic-v2-sr.c    |  78 +++-------------------------
 virt/kvm/arm/hyp/vgic-v3-sr.c    |  79 +++++++---------------------
 virt/kvm/arm/vgic/vgic-init.c    | 108 ++++++++++++++++++++++++---------------
 virt/kvm/arm/vgic/vgic-v2.c      | 101 ++++++++++++++++++++----------------
 virt/kvm/arm/vgic/vgic-v3.c      |  89 +++++++++++++++++++-------------
 virt/kvm/arm/vgic/vgic.c         |  44 +++++++++++++---
 virt/kvm/arm/vgic/vgic.h         |  10 +++-
 11 files changed, 261 insertions(+), 273 deletions(-)

-- 
2.9.0

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

* [PATCH 0/9] KVM: arm/arm64: vgic: Improvements and optimizations
@ 2017-03-20 10:58 ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

We can improve the performance of our VGIC implementation a bit and
clean up a lot of the implementation while we're at it.

At first, patch 1 may seem excessive for a single register, the VMCR,
but whlie it adds complexity it does move logic out of the critical path
and into the vcpu_load/put hooks, which are executed much more rarely.
It also provides an infrastructure to move more things into the
vgic_load/put functions later one.

Avoiding the need to take a spinlock in the common case where there are
no virtual interrupts in flight are actually measurable and well worth
the effort.

The implementation cleanups boil down to maintaining a single count of
the used lrs instead of an additional bitmap, avoiding the need to deel
with the MISR and EISR fields, and doing an early init of the VGIC to
avoid a number of vgic_initialized() checks.

Tested on Mustang and TC2, and Thunder-X.

Patches also available on:
git://git.kernel.org/pub/scm/linux/kernel/git/cdall/linux.git gic-optimize

Thanks,
-Christoffer

Christoffer Dall (8):
  KVM: arm/arm64: vgic: Defer touching GICH_VMCR to vcpu_load/put
  KVM: arm/arm64: vgic: Get rid of live_lrs
  KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance
    operation
  KVM: arm/arm64: vgic: Get rid of unnecessary save_maint_int_state
  KVM: arm/arm64: vgic: Get rid of MISR and EISR fields
  KVM: arm/arm64: vgic: Implement early VGIC init functionality
  KVM: arm/arm64: vgic: Don't check vgic_initialized in flush_hwstate
  KVM: arm/arm64: vgic: Improve sync_hwstate performance

Shih-Wei Li (1):
  KVM: arm/arm64: vgic: Avoid flushing vgic state when there's no
    pending IRQ

 arch/arm/include/asm/kvm_asm.h   |   3 ++
 arch/arm/kvm/arm.c               |  11 ++--
 arch/arm64/include/asm/kvm_asm.h |   2 +
 include/kvm/arm_vgic.h           |   9 ++--
 virt/kvm/arm/hyp/vgic-v2-sr.c    |  78 +++-------------------------
 virt/kvm/arm/hyp/vgic-v3-sr.c    |  79 +++++++---------------------
 virt/kvm/arm/vgic/vgic-init.c    | 108 ++++++++++++++++++++++++---------------
 virt/kvm/arm/vgic/vgic-v2.c      | 101 ++++++++++++++++++++----------------
 virt/kvm/arm/vgic/vgic-v3.c      |  89 +++++++++++++++++++-------------
 virt/kvm/arm/vgic/vgic.c         |  44 +++++++++++++---
 virt/kvm/arm/vgic/vgic.h         |  10 +++-
 11 files changed, 261 insertions(+), 273 deletions(-)

-- 
2.9.0

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

* [PATCH 1/9] KVM: arm/arm64: vgic: Defer touching GICH_VMCR to vcpu_load/put
  2017-03-20 10:58 ` Christoffer Dall
@ 2017-03-20 10:58   ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Christoffer Dall, kvm, Christoffer Dall, Marc Zyngier, Andre Przywara

From: Christoffer Dall <cdall@cs.columbia.edu>

We don't have to save/restore the VMCR on every entry to/from the guest,
since on GICv2 we can access the control interface from EL1 and on VHE
systems with GICv3 we can access the control interface from KVM running
in EL2.

GICv3 systems without VHE becomes the rare case, which has to
save/restore the register on each round trip.

For in-context accesses to the VMCR, meaning emulation code needs access
to the value of the VCPU that is currently running within vcpu_load
and vcpu_put will detect that the it should load the VMCR from the
physical GIC instead of using the cached memory value.  While this extra
checking adds some code complexity we end up moving code out of the
critical path.

Note that userspace accesses may see out-of-date values if the VCPU is
running while accessing the VGIC state via the KVM device API, but this
is already the case.

Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
Signed-off-by: Christoffer Dall <cdall@linaro.org>
---
 arch/arm/include/asm/kvm_asm.h   |  3 +++
 arch/arm/kvm/arm.c               | 11 +++++-----
 arch/arm64/include/asm/kvm_asm.h |  2 ++
 include/kvm/arm_vgic.h           |  3 +++
 virt/kvm/arm/hyp/vgic-v2-sr.c    |  3 ---
 virt/kvm/arm/hyp/vgic-v3-sr.c    | 14 ++++++++----
 virt/kvm/arm/vgic/vgic-init.c    | 12 +++++++++++
 virt/kvm/arm/vgic/vgic-v2.c      | 46 ++++++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic-v3.c      | 42 ++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic.c         | 22 +++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h         |  6 ++++++
 11 files changed, 148 insertions(+), 16 deletions(-)

diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 8ef0538..dd16044 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -75,7 +75,10 @@ extern void __init_stage2_translation(void);
 extern void __kvm_hyp_reset(unsigned long);
 
 extern u64 __vgic_v3_get_ich_vtr_el2(void);
+extern u64 __vgic_v3_read_vmcr(void);
+extern void __vgic_v3_write_vmcr(u32 vmcr);
 extern void __vgic_v3_init_lrs(void);
+
 #endif
 
 #endif /* __ARM_KVM_ASM_H__ */
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index d775aac..cfdf2f5 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -348,15 +348,14 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 	vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
 
 	kvm_arm_set_running_vcpu(vcpu);
+
+	kvm_vgic_load(vcpu);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
-	/*
-	 * The arch-generic KVM code expects the cpu field of a vcpu to be -1
-	 * if the vcpu is no longer assigned to a cpu.  This is used for the
-	 * optimized make_all_cpus_request path.
-	 */
+	kvm_vgic_put(vcpu);
+
 	vcpu->cpu = -1;
 
 	kvm_arm_set_running_vcpu(NULL);
@@ -630,7 +629,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		 * non-preemptible context.
 		 */
 		preempt_disable();
+
 		kvm_pmu_flush_hwstate(vcpu);
+
 		kvm_timer_flush_hwstate(vcpu);
 		kvm_vgic_flush_hwstate(vcpu);
 
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index ec3553eb..49f99cd 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -59,6 +59,8 @@ extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
 extern u64 __vgic_v3_get_ich_vtr_el2(void);
+extern u64 __vgic_v3_read_vmcr(void);
+extern void __vgic_v3_write_vmcr(u32 vmcr);
 extern void __vgic_v3_init_lrs(void);
 
 extern u32 __kvm_get_mdcr_el2(void);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index c0b3d99..8d7c3a7 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -307,6 +307,9 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
+void kvm_vgic_load(struct kvm_vcpu *vcpu);
+void kvm_vgic_put(struct kvm_vcpu *vcpu);
+
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index c8aeb7b..d3d3b9b 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -114,8 +114,6 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
 	if (!base)
 		return;
 
-	cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
-
 	if (vcpu->arch.vgic_cpu.live_lrs) {
 		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
 
@@ -165,7 +163,6 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
 		}
 	}
 
-	writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
 	vcpu->arch.vgic_cpu.live_lrs = live_lrs;
 }
 
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 3947095..e51ee7e 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -159,8 +159,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 	if (!cpu_if->vgic_sre)
 		dsb(st);
 
-	cpu_if->vgic_vmcr  = read_gicreg(ICH_VMCR_EL2);
-
 	if (vcpu->arch.vgic_cpu.live_lrs) {
 		int i;
 		u32 max_lr_idx, nr_pri_bits;
@@ -261,8 +259,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 			live_lrs |= (1 << i);
 	}
 
-	write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
-
 	if (live_lrs) {
 		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 
@@ -326,3 +322,13 @@ u64 __hyp_text __vgic_v3_get_ich_vtr_el2(void)
 {
 	return read_gicreg(ICH_VTR_EL2);
 }
+
+u64 __hyp_text __vgic_v3_read_vmcr(void)
+{
+	return read_gicreg(ICH_VMCR_EL2);
+}
+
+void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
+{
+	write_gicreg(vmcr, ICH_VMCR_EL2);
+}
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 702f810..3762fd1 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -262,6 +262,18 @@ int vgic_init(struct kvm *kvm)
 	vgic_debug_init(kvm);
 
 	dist->initialized = true;
+
+	/*
+	 * If we're initializing GICv2 on-demand when first running the VCPU
+	 * then we need to load the VGIC state onto the CPU.  We can detect
+	 * this easily by checking if we are in between vcpu_load and vcpu_put
+	 * when we just initialized the VGIC.
+	 */
+	preempt_disable();
+	vcpu = kvm_arm_get_running_vcpu();
+	if (vcpu)
+		kvm_vgic_load(vcpu);
+	preempt_enable();
 out:
 	return ret;
 }
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 94cf4b9..dfe6e5e 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -199,6 +199,9 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
 
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
+	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	int cpu;
 	u32 vmcr;
 
 	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
@@ -209,12 +212,35 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
 		GICH_VMCR_PRIMASK_MASK;
 
-	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
+	cpu_if->vgic_vmcr = vmcr;
+
+	cpu = get_cpu();
+	if (vcpu->cpu == cpu)
+		/*
+		 * We have run vcpu_load and we're on VHE which means the VMCR
+		 * has already been flushed to the CPU; flush it again.
+		 */
+		writel_relaxed(vmcr, vgic->vctrl_base + GICH_VMCR);
+	put_cpu();
 }
 
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
-	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
+	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	int cpu;
+	u32 vmcr;
+
+	cpu = get_cpu();
+	if (vcpu->cpu == cpu)
+		/*
+		 * We have run vcpu_load and which means the VMCR
+		 * has already been flushed to the CPU; sync it back.
+		 */
+		cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
+	put_cpu();
+
+	vmcr = cpu_if->vgic_vmcr;
 
 	vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >>
 			GICH_VMCR_CTRL_SHIFT;
@@ -390,3 +416,19 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
 
 	return ret;
 }
+
+void vgic_v2_load(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
+
+	writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
+}
+
+void vgic_v2_put(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
+
+	cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
+}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index edc6ee2..3d7796c 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -173,7 +173,9 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
 
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
 	u32 vmcr;
+	int cpu;
 
 	/*
 	 * Ignore the FIQen bit, because GIC emulation always implies
@@ -188,12 +190,34 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
 	vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
 
-	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
+	cpu_if->vgic_vmcr = vmcr;
+
+	cpu = get_cpu();
+	if (vcpu->cpu == cpu)
+		/*
+		 * We have run vcpu_load which means the VMCR
+		 * has already been flushed to the CPU; flush it again.
+		 */
+		kvm_call_hyp(__vgic_v3_write_vmcr, vmcr);
+	put_cpu();
 }
 
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
-	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+	int cpu;
+	u32 vmcr;
+
+	cpu = get_cpu();
+	if (vcpu->cpu == cpu)
+		/*
+		 * We have run vcpu_load and which means the VMCR
+		 * has already been flushed to the CPU; sync it back.
+		 */
+		cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
+	put_cpu();
+
+	vmcr = cpu_if->vgic_vmcr;
 
 	/*
 	 * Ignore the FIQen bit, because GIC emulation always implies
@@ -383,3 +407,17 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 
 	return 0;
 }
+
+void vgic_v3_load(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
+}
+
+void vgic_v3_put(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 654dfd4..2ac0def 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -656,6 +656,28 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
 }
 
+void kvm_vgic_load(struct kvm_vcpu *vcpu)
+{
+	if (unlikely(!vgic_initialized(vcpu->kvm)))
+		return;
+
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_load(vcpu);
+	else
+		vgic_v3_load(vcpu);
+}
+
+void kvm_vgic_put(struct kvm_vcpu *vcpu)
+{
+	if (unlikely(!vgic_initialized(vcpu->kvm)))
+		return;
+
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_put(vcpu);
+	else
+		vgic_v3_put(vcpu);
+}
+
 int kvm_vgic_vcpu_pending_irq(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 91566f5..3f64220 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -132,6 +132,9 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 
 void vgic_v2_init_lrs(void);
 
+void vgic_v2_load(struct kvm_vcpu *vcpu);
+void vgic_v2_put(struct kvm_vcpu *vcpu);
+
 static inline void vgic_get_irq_kref(struct vgic_irq *irq)
 {
 	if (irq->intid < VGIC_MIN_LPI)
@@ -152,6 +155,9 @@ int vgic_v3_probe(const struct gic_kvm_info *info);
 int vgic_v3_map_resources(struct kvm *kvm);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 
+void vgic_v3_load(struct kvm_vcpu *vcpu);
+void vgic_v3_put(struct kvm_vcpu *vcpu);
+
 int vgic_register_its_iodevs(struct kvm *kvm);
 bool vgic_has_its(struct kvm *kvm);
 int kvm_vgic_register_its_device(void);
-- 
2.9.0

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

* [PATCH 1/9] KVM: arm/arm64: vgic: Defer touching GICH_VMCR to vcpu_load/put
@ 2017-03-20 10:58   ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

From: Christoffer Dall <cdall@cs.columbia.edu>

We don't have to save/restore the VMCR on every entry to/from the guest,
since on GICv2 we can access the control interface from EL1 and on VHE
systems with GICv3 we can access the control interface from KVM running
in EL2.

GICv3 systems without VHE becomes the rare case, which has to
save/restore the register on each round trip.

For in-context accesses to the VMCR, meaning emulation code needs access
to the value of the VCPU that is currently running within vcpu_load
and vcpu_put will detect that the it should load the VMCR from the
physical GIC instead of using the cached memory value.  While this extra
checking adds some code complexity we end up moving code out of the
critical path.

Note that userspace accesses may see out-of-date values if the VCPU is
running while accessing the VGIC state via the KVM device API, but this
is already the case.

Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
Signed-off-by: Christoffer Dall <cdall@linaro.org>
---
 arch/arm/include/asm/kvm_asm.h   |  3 +++
 arch/arm/kvm/arm.c               | 11 +++++-----
 arch/arm64/include/asm/kvm_asm.h |  2 ++
 include/kvm/arm_vgic.h           |  3 +++
 virt/kvm/arm/hyp/vgic-v2-sr.c    |  3 ---
 virt/kvm/arm/hyp/vgic-v3-sr.c    | 14 ++++++++----
 virt/kvm/arm/vgic/vgic-init.c    | 12 +++++++++++
 virt/kvm/arm/vgic/vgic-v2.c      | 46 ++++++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic-v3.c      | 42 ++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic.c         | 22 +++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h         |  6 ++++++
 11 files changed, 148 insertions(+), 16 deletions(-)

diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 8ef0538..dd16044 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -75,7 +75,10 @@ extern void __init_stage2_translation(void);
 extern void __kvm_hyp_reset(unsigned long);
 
 extern u64 __vgic_v3_get_ich_vtr_el2(void);
+extern u64 __vgic_v3_read_vmcr(void);
+extern void __vgic_v3_write_vmcr(u32 vmcr);
 extern void __vgic_v3_init_lrs(void);
+
 #endif
 
 #endif /* __ARM_KVM_ASM_H__ */
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index d775aac..cfdf2f5 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -348,15 +348,14 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 	vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
 
 	kvm_arm_set_running_vcpu(vcpu);
+
+	kvm_vgic_load(vcpu);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
-	/*
-	 * The arch-generic KVM code expects the cpu field of a vcpu to be -1
-	 * if the vcpu is no longer assigned to a cpu.  This is used for the
-	 * optimized make_all_cpus_request path.
-	 */
+	kvm_vgic_put(vcpu);
+
 	vcpu->cpu = -1;
 
 	kvm_arm_set_running_vcpu(NULL);
@@ -630,7 +629,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		 * non-preemptible context.
 		 */
 		preempt_disable();
+
 		kvm_pmu_flush_hwstate(vcpu);
+
 		kvm_timer_flush_hwstate(vcpu);
 		kvm_vgic_flush_hwstate(vcpu);
 
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index ec3553eb..49f99cd 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -59,6 +59,8 @@ extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
 extern u64 __vgic_v3_get_ich_vtr_el2(void);
+extern u64 __vgic_v3_read_vmcr(void);
+extern void __vgic_v3_write_vmcr(u32 vmcr);
 extern void __vgic_v3_init_lrs(void);
 
 extern u32 __kvm_get_mdcr_el2(void);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index c0b3d99..8d7c3a7 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -307,6 +307,9 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
+void kvm_vgic_load(struct kvm_vcpu *vcpu);
+void kvm_vgic_put(struct kvm_vcpu *vcpu);
+
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index c8aeb7b..d3d3b9b 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -114,8 +114,6 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
 	if (!base)
 		return;
 
-	cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
-
 	if (vcpu->arch.vgic_cpu.live_lrs) {
 		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
 
@@ -165,7 +163,6 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
 		}
 	}
 
-	writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
 	vcpu->arch.vgic_cpu.live_lrs = live_lrs;
 }
 
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 3947095..e51ee7e 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -159,8 +159,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 	if (!cpu_if->vgic_sre)
 		dsb(st);
 
-	cpu_if->vgic_vmcr  = read_gicreg(ICH_VMCR_EL2);
-
 	if (vcpu->arch.vgic_cpu.live_lrs) {
 		int i;
 		u32 max_lr_idx, nr_pri_bits;
@@ -261,8 +259,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 			live_lrs |= (1 << i);
 	}
 
-	write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
-
 	if (live_lrs) {
 		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 
@@ -326,3 +322,13 @@ u64 __hyp_text __vgic_v3_get_ich_vtr_el2(void)
 {
 	return read_gicreg(ICH_VTR_EL2);
 }
+
+u64 __hyp_text __vgic_v3_read_vmcr(void)
+{
+	return read_gicreg(ICH_VMCR_EL2);
+}
+
+void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
+{
+	write_gicreg(vmcr, ICH_VMCR_EL2);
+}
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 702f810..3762fd1 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -262,6 +262,18 @@ int vgic_init(struct kvm *kvm)
 	vgic_debug_init(kvm);
 
 	dist->initialized = true;
+
+	/*
+	 * If we're initializing GICv2 on-demand when first running the VCPU
+	 * then we need to load the VGIC state onto the CPU.  We can detect
+	 * this easily by checking if we are in between vcpu_load and vcpu_put
+	 * when we just initialized the VGIC.
+	 */
+	preempt_disable();
+	vcpu = kvm_arm_get_running_vcpu();
+	if (vcpu)
+		kvm_vgic_load(vcpu);
+	preempt_enable();
 out:
 	return ret;
 }
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 94cf4b9..dfe6e5e 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -199,6 +199,9 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
 
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
+	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	int cpu;
 	u32 vmcr;
 
 	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
@@ -209,12 +212,35 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
 		GICH_VMCR_PRIMASK_MASK;
 
-	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
+	cpu_if->vgic_vmcr = vmcr;
+
+	cpu = get_cpu();
+	if (vcpu->cpu == cpu)
+		/*
+		 * We have run vcpu_load and we're on VHE which means the VMCR
+		 * has already been flushed to the CPU; flush it again.
+		 */
+		writel_relaxed(vmcr, vgic->vctrl_base + GICH_VMCR);
+	put_cpu();
 }
 
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
-	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
+	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	int cpu;
+	u32 vmcr;
+
+	cpu = get_cpu();
+	if (vcpu->cpu == cpu)
+		/*
+		 * We have run vcpu_load and which means the VMCR
+		 * has already been flushed to the CPU; sync it back.
+		 */
+		cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
+	put_cpu();
+
+	vmcr = cpu_if->vgic_vmcr;
 
 	vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >>
 			GICH_VMCR_CTRL_SHIFT;
@@ -390,3 +416,19 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
 
 	return ret;
 }
+
+void vgic_v2_load(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
+
+	writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
+}
+
+void vgic_v2_put(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
+
+	cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
+}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index edc6ee2..3d7796c 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -173,7 +173,9 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
 
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
 	u32 vmcr;
+	int cpu;
 
 	/*
 	 * Ignore the FIQen bit, because GIC emulation always implies
@@ -188,12 +190,34 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
 	vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
 
-	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
+	cpu_if->vgic_vmcr = vmcr;
+
+	cpu = get_cpu();
+	if (vcpu->cpu == cpu)
+		/*
+		 * We have run vcpu_load which means the VMCR
+		 * has already been flushed to the CPU; flush it again.
+		 */
+		kvm_call_hyp(__vgic_v3_write_vmcr, vmcr);
+	put_cpu();
 }
 
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
-	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+	int cpu;
+	u32 vmcr;
+
+	cpu = get_cpu();
+	if (vcpu->cpu == cpu)
+		/*
+		 * We have run vcpu_load and which means the VMCR
+		 * has already been flushed to the CPU; sync it back.
+		 */
+		cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
+	put_cpu();
+
+	vmcr = cpu_if->vgic_vmcr;
 
 	/*
 	 * Ignore the FIQen bit, because GIC emulation always implies
@@ -383,3 +407,17 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 
 	return 0;
 }
+
+void vgic_v3_load(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
+}
+
+void vgic_v3_put(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 654dfd4..2ac0def 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -656,6 +656,28 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
 }
 
+void kvm_vgic_load(struct kvm_vcpu *vcpu)
+{
+	if (unlikely(!vgic_initialized(vcpu->kvm)))
+		return;
+
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_load(vcpu);
+	else
+		vgic_v3_load(vcpu);
+}
+
+void kvm_vgic_put(struct kvm_vcpu *vcpu)
+{
+	if (unlikely(!vgic_initialized(vcpu->kvm)))
+		return;
+
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_put(vcpu);
+	else
+		vgic_v3_put(vcpu);
+}
+
 int kvm_vgic_vcpu_pending_irq(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 91566f5..3f64220 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -132,6 +132,9 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 
 void vgic_v2_init_lrs(void);
 
+void vgic_v2_load(struct kvm_vcpu *vcpu);
+void vgic_v2_put(struct kvm_vcpu *vcpu);
+
 static inline void vgic_get_irq_kref(struct vgic_irq *irq)
 {
 	if (irq->intid < VGIC_MIN_LPI)
@@ -152,6 +155,9 @@ int vgic_v3_probe(const struct gic_kvm_info *info);
 int vgic_v3_map_resources(struct kvm *kvm);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 
+void vgic_v3_load(struct kvm_vcpu *vcpu);
+void vgic_v3_put(struct kvm_vcpu *vcpu);
+
 int vgic_register_its_iodevs(struct kvm *kvm);
 bool vgic_has_its(struct kvm *kvm);
 int kvm_vgic_register_its_device(void);
-- 
2.9.0

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

* [PATCH 2/9] KVM: arm/arm64: vgic: Avoid flushing vgic state when there's no pending IRQ
  2017-03-20 10:58 ` Christoffer Dall
@ 2017-03-20 10:58   ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Christoffer Dall, kvm, Marc Zyngier, Andre Przywara, Shih-Wei Li

From: Shih-Wei Li <shihwei@cs.columbia.edu>

We do not need to flush vgic states in each world switch unless
there is pending IRQ queued to the vgic's ap list. We can thus reduce
the overhead by not grabbing the spinlock and not making the extra
function call to vgic_flush_lr_state.

Signed-off-by: Shih-Wei Li <shihwei@cs.columbia.edu>
Signed-off-by: Christoffer Dall <cdall@linaro.org>
---
 virt/kvm/arm/vgic/vgic.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 2ac0def..1436c2e 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -637,12 +637,17 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 /* Sync back the hardware VGIC state into our emulation after a guest's run. */
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
 	if (unlikely(!vgic_initialized(vcpu->kvm)))
 		return;
 
 	vgic_process_maintenance_interrupt(vcpu);
 	vgic_fold_lr_state(vcpu);
 	vgic_prune_ap_list(vcpu);
+
+	/* Make sure we can fast-path in flush_hwstate */
+	vgic_cpu->used_lrs = 0;
 }
 
 /* Flush our emulation state into the GIC hardware before entering the guest. */
@@ -651,6 +656,9 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	if (unlikely(!vgic_initialized(vcpu->kvm)))
 		return;
 
+	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
+		return;
+
 	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
 	vgic_flush_lr_state(vcpu);
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
-- 
2.9.0

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

* [PATCH 2/9] KVM: arm/arm64: vgic: Avoid flushing vgic state when there's no pending IRQ
@ 2017-03-20 10:58   ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shih-Wei Li <shihwei@cs.columbia.edu>

We do not need to flush vgic states in each world switch unless
there is pending IRQ queued to the vgic's ap list. We can thus reduce
the overhead by not grabbing the spinlock and not making the extra
function call to vgic_flush_lr_state.

Signed-off-by: Shih-Wei Li <shihwei@cs.columbia.edu>
Signed-off-by: Christoffer Dall <cdall@linaro.org>
---
 virt/kvm/arm/vgic/vgic.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 2ac0def..1436c2e 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -637,12 +637,17 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 /* Sync back the hardware VGIC state into our emulation after a guest's run. */
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
 	if (unlikely(!vgic_initialized(vcpu->kvm)))
 		return;
 
 	vgic_process_maintenance_interrupt(vcpu);
 	vgic_fold_lr_state(vcpu);
 	vgic_prune_ap_list(vcpu);
+
+	/* Make sure we can fast-path in flush_hwstate */
+	vgic_cpu->used_lrs = 0;
 }
 
 /* Flush our emulation state into the GIC hardware before entering the guest. */
@@ -651,6 +656,9 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	if (unlikely(!vgic_initialized(vcpu->kvm)))
 		return;
 
+	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
+		return;
+
 	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
 	vgic_flush_lr_state(vcpu);
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
-- 
2.9.0

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

* [PATCH 3/9] KVM: arm/arm64: vgic: Get rid of live_lrs
  2017-03-20 10:58 ` Christoffer Dall
@ 2017-03-20 10:58   ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

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

There is no need to calculate and maintain live_lrs when we always
populate the lowest numbered LRs first on every entry and clear all LRs
on every exit.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 include/kvm/arm_vgic.h        |  2 --
 virt/kvm/arm/hyp/vgic-v2-sr.c | 39 ++++++++++-----------------------------
 virt/kvm/arm/hyp/vgic-v3-sr.c | 42 ++++++++++++------------------------------
 3 files changed, 22 insertions(+), 61 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 8d7c3a7..fa12d99 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -264,8 +264,6 @@ struct vgic_cpu {
 	 */
 	struct list_head ap_list_head;
 
-	u64 live_lrs;
-
 	/*
 	 * Members below are used with GICv3 emulation only and represent
 	 * parts of the redistributor.
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index d3d3b9b..34b37ce 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -26,27 +26,23 @@ 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 = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 	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;
-
+	for (i = 0; i < used_lrs && !expect_mi; i++)
 		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))
+			if (unlikely(used_lrs > 32))
 				eisr1  = readl_relaxed(base + GICH_EISR1);
 			else
 				eisr1 = 0;
@@ -87,13 +83,10 @@ 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 = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
 	int i;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 
-	for (i = 0; i < nr_lr; i++) {
-		if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
-			continue;
-
+	for (i = 0; i < used_lrs; i++) {
 		if (cpu_if->vgic_elrsr & (1UL << i))
 			cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
 		else
@@ -110,11 +103,12 @@ 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);
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 
 	if (!base)
 		return;
 
-	if (vcpu->arch.vgic_cpu.live_lrs) {
+	if (used_lrs) {
 		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
 
 		save_maint_int_state(vcpu, base);
@@ -122,8 +116,6 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
 		save_lrs(vcpu, base);
 
 		writel_relaxed(0, base + GICH_HCR);
-
-		vcpu->arch.vgic_cpu.live_lrs = 0;
 	} else {
 		cpu_if->vgic_eisr = 0;
 		cpu_if->vgic_elrsr = ~0UL;
@@ -139,31 +131,20 @@ 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 nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
 	int i;
-	u64 live_lrs = 0;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 
 	if (!base)
 		return;
 
-
-	for (i = 0; i < nr_lr; i++)
-		if (cpu_if->vgic_lr[i] & GICH_LR_STATE)
-			live_lrs |= 1UL << i;
-
-	if (live_lrs) {
+	if (used_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++) {
-			if (!(live_lrs & (1UL << i)))
-				continue;
-
+		for (i = 0; i < used_lrs; i++) {
 			writel_relaxed(cpu_if->vgic_lr[i],
 				       base + GICH_LR0 + (i * 4));
 		}
 	}
-
-	vcpu->arch.vgic_cpu.live_lrs = live_lrs;
 }
 
 #ifdef CONFIG_ARM64
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index e51ee7e..b3c36b6 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -118,18 +118,16 @@ 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)
+static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
 	int i;
 	bool expect_mi;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 
 	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;
-
+	for (i = 0; i < used_lrs; i++) {
 		expect_mi |= (!(cpu_if->vgic_lr[i] & ICH_LR_HW) &&
 			      (cpu_if->vgic_lr[i] & ICH_LR_EOI));
 	}
@@ -150,6 +148,7 @@ static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu, int nr_lr)
 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 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 	u64 val;
 
 	/*
@@ -159,23 +158,19 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 	if (!cpu_if->vgic_sre)
 		dsb(st);
 
-	if (vcpu->arch.vgic_cpu.live_lrs) {
+	if (used_lrs) {
 		int i;
-		u32 max_lr_idx, nr_pri_bits;
+		u32 nr_pri_bits;
 
 		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);
 
-		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)))
-				continue;
+		save_maint_int_state(vcpu);
 
+		for (i = 0; i <= used_lrs; i++) {
 			if (cpu_if->vgic_elrsr & (1 << i))
 				cpu_if->vgic_lr[i] &= ~ICH_LR_STATE;
 			else
@@ -203,8 +198,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 		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;
@@ -232,9 +225,9 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 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 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 	u64 val;
-	u32 max_lr_idx, nr_pri_bits;
-	u16 live_lrs = 0;
+	u32 nr_pri_bits;
 	int i;
 
 	/*
@@ -251,15 +244,9 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 	}
 
 	val = read_gicreg(ICH_VTR_EL2);
-	max_lr_idx = vtr_to_max_lr_idx(val);
 	nr_pri_bits = vtr_to_nr_pri_bits(val);
 
-	for (i = 0; i <= max_lr_idx; i++) {
-		if (cpu_if->vgic_lr[i] & ICH_LR_STATE)
-			live_lrs |= (1 << i);
-	}
-
-	if (live_lrs) {
+	if (used_lrs) {
 		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 
 		switch (nr_pri_bits) {
@@ -282,12 +269,8 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 			write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
 		}
 
-		for (i = 0; i <= max_lr_idx; i++) {
-			if (!(live_lrs & (1 << i)))
-				continue;
-
+		for (i = 0; i < used_lrs; i++)
 			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
-		}
 	}
 
 	/*
@@ -299,7 +282,6 @@ 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
-- 
2.9.0

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

* [PATCH 3/9] KVM: arm/arm64: vgic: Get rid of live_lrs
@ 2017-03-20 10:58   ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

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

There is no need to calculate and maintain live_lrs when we always
populate the lowest numbered LRs first on every entry and clear all LRs
on every exit.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 include/kvm/arm_vgic.h        |  2 --
 virt/kvm/arm/hyp/vgic-v2-sr.c | 39 ++++++++++-----------------------------
 virt/kvm/arm/hyp/vgic-v3-sr.c | 42 ++++++++++++------------------------------
 3 files changed, 22 insertions(+), 61 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 8d7c3a7..fa12d99 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -264,8 +264,6 @@ struct vgic_cpu {
 	 */
 	struct list_head ap_list_head;
 
-	u64 live_lrs;
-
 	/*
 	 * Members below are used with GICv3 emulation only and represent
 	 * parts of the redistributor.
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index d3d3b9b..34b37ce 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -26,27 +26,23 @@ 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 = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 	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;
-
+	for (i = 0; i < used_lrs && !expect_mi; i++)
 		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))
+			if (unlikely(used_lrs > 32))
 				eisr1  = readl_relaxed(base + GICH_EISR1);
 			else
 				eisr1 = 0;
@@ -87,13 +83,10 @@ 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 = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
 	int i;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 
-	for (i = 0; i < nr_lr; i++) {
-		if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
-			continue;
-
+	for (i = 0; i < used_lrs; i++) {
 		if (cpu_if->vgic_elrsr & (1UL << i))
 			cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
 		else
@@ -110,11 +103,12 @@ 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);
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 
 	if (!base)
 		return;
 
-	if (vcpu->arch.vgic_cpu.live_lrs) {
+	if (used_lrs) {
 		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
 
 		save_maint_int_state(vcpu, base);
@@ -122,8 +116,6 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
 		save_lrs(vcpu, base);
 
 		writel_relaxed(0, base + GICH_HCR);
-
-		vcpu->arch.vgic_cpu.live_lrs = 0;
 	} else {
 		cpu_if->vgic_eisr = 0;
 		cpu_if->vgic_elrsr = ~0UL;
@@ -139,31 +131,20 @@ 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 nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
 	int i;
-	u64 live_lrs = 0;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 
 	if (!base)
 		return;
 
-
-	for (i = 0; i < nr_lr; i++)
-		if (cpu_if->vgic_lr[i] & GICH_LR_STATE)
-			live_lrs |= 1UL << i;
-
-	if (live_lrs) {
+	if (used_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++) {
-			if (!(live_lrs & (1UL << i)))
-				continue;
-
+		for (i = 0; i < used_lrs; i++) {
 			writel_relaxed(cpu_if->vgic_lr[i],
 				       base + GICH_LR0 + (i * 4));
 		}
 	}
-
-	vcpu->arch.vgic_cpu.live_lrs = live_lrs;
 }
 
 #ifdef CONFIG_ARM64
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index e51ee7e..b3c36b6 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -118,18 +118,16 @@ 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)
+static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
 	int i;
 	bool expect_mi;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 
 	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;
-
+	for (i = 0; i < used_lrs; i++) {
 		expect_mi |= (!(cpu_if->vgic_lr[i] & ICH_LR_HW) &&
 			      (cpu_if->vgic_lr[i] & ICH_LR_EOI));
 	}
@@ -150,6 +148,7 @@ static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu, int nr_lr)
 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 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 	u64 val;
 
 	/*
@@ -159,23 +158,19 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 	if (!cpu_if->vgic_sre)
 		dsb(st);
 
-	if (vcpu->arch.vgic_cpu.live_lrs) {
+	if (used_lrs) {
 		int i;
-		u32 max_lr_idx, nr_pri_bits;
+		u32 nr_pri_bits;
 
 		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);
 
-		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)))
-				continue;
+		save_maint_int_state(vcpu);
 
+		for (i = 0; i <= used_lrs; i++) {
 			if (cpu_if->vgic_elrsr & (1 << i))
 				cpu_if->vgic_lr[i] &= ~ICH_LR_STATE;
 			else
@@ -203,8 +198,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 		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;
@@ -232,9 +225,9 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 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 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 	u64 val;
-	u32 max_lr_idx, nr_pri_bits;
-	u16 live_lrs = 0;
+	u32 nr_pri_bits;
 	int i;
 
 	/*
@@ -251,15 +244,9 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 	}
 
 	val = read_gicreg(ICH_VTR_EL2);
-	max_lr_idx = vtr_to_max_lr_idx(val);
 	nr_pri_bits = vtr_to_nr_pri_bits(val);
 
-	for (i = 0; i <= max_lr_idx; i++) {
-		if (cpu_if->vgic_lr[i] & ICH_LR_STATE)
-			live_lrs |= (1 << i);
-	}
-
-	if (live_lrs) {
+	if (used_lrs) {
 		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 
 		switch (nr_pri_bits) {
@@ -282,12 +269,8 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 			write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
 		}
 
-		for (i = 0; i <= max_lr_idx; i++) {
-			if (!(live_lrs & (1 << i)))
-				continue;
-
+		for (i = 0; i < used_lrs; i++)
 			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
-		}
 	}
 
 	/*
@@ -299,7 +282,6 @@ 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
-- 
2.9.0

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

* [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operation
  2017-03-20 10:58 ` Christoffer Dall
@ 2017-03-20 10:58   ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

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

Since we always read back the LRs that we wrote to the guest and the
MISR and EISR registers simply provide a summary of the configuration of
the bits in the LRs, there is really no need to read back those status
registers and process them.  We can might as well just signal the
notifyfd when folding the LR state and save some cycles in the process.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/vgic/vgic-v2.c | 55 ++++++++++-----------------------------------
 virt/kvm/arm/vgic/vgic-v3.c | 47 +++++++++++---------------------------
 virt/kvm/arm/vgic/vgic.c    |  8 +++----
 virt/kvm/arm/vgic/vgic.h    |  4 ++--
 4 files changed, 31 insertions(+), 83 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index dfe6e5e..0172754 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -22,20 +22,6 @@
 
 #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;
-}
-
 static inline void vgic_v2_write_lr(int lr, u32 val)
 {
 	void __iomem *base = kvm_vgic_global_state.vctrl_base;
@@ -51,38 +37,10 @@ void vgic_v2_init_lrs(void)
 		vgic_v2_write_lr(i, 0);
 }
 
-void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
+void vgic_v2_clear_uie(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);
-
-			/* Only SPIs require notification */
-			if (vgic_valid_spi(vcpu->kvm, intid))
-				kvm_notify_acked_irq(vcpu->kvm, 0,
-						     intid - VGIC_NR_PRIVATE_IRQS);
-		}
-	}
-
-	/* 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)
@@ -92,6 +50,12 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
 	cpuif->vgic_hcr |= GICH_HCR_UIE;
 }
 
+static bool lr_signals_eoi_mi(u32 lr_val)
+{
+	return !(lr_val & GICH_LR_STATE) && (lr_val & GICH_LR_EOI) &&
+	       !(lr_val & GICH_LR_HW);
+}
+
 /*
  * transfer the content of the LRs back into the corresponding ap_list:
  * - active bit is transferred as is
@@ -109,6 +73,11 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
 		u32 intid = val & GICH_LR_VIRTUALID;
 		struct vgic_irq *irq;
 
+		/* Notify fds when the guest EOI'ed a level-triggered SPI */
+		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
 		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
 
 		spin_lock(&irq->irq_lock);
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 3d7796c..7880c5c 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -21,42 +21,9 @@
 
 #include "vgic.h"
 
-void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
+void vgic_v3_clear_uie(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);
-
-			/* Only SPIs require notification */
-			if (vgic_valid_spi(vcpu->kvm, intid))
-				kvm_notify_acked_irq(vcpu->kvm, 0,
-						     intid - VGIC_NR_PRIVATE_IRQS);
-		}
-
-		/*
-		 * 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;
 }
 
@@ -67,6 +34,12 @@ void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 	cpuif->vgic_hcr |= ICH_HCR_UIE;
 }
 
+static bool lr_signals_eoi_mi(u64 lr_val)
+{
+	return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) &&
+	       !(lr_val & ICH_LR_HW);
+}
+
 void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -82,6 +55,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 			intid = val & ICH_LR_VIRTUAL_ID_MASK;
 		else
 			intid = val & GICH_LR_VIRTUALID;
+
+		/* Notify fds when the guest EOI'ed a level-triggered IRQ */
+		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
 		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
 		if (!irq)	/* An LPI could have been unmapped. */
 			continue;
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 1436c2e..f5b3c25 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -527,12 +527,12 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
 	spin_unlock(&vgic_cpu->ap_list_lock);
 }
 
-static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
+static inline void vgic_clear_uie(struct kvm_vcpu *vcpu)
 {
 	if (kvm_vgic_global_state.type == VGIC_V2)
-		vgic_v2_process_maintenance(vcpu);
+		vgic_v2_clear_uie(vcpu);
 	else
-		vgic_v3_process_maintenance(vcpu);
+		vgic_v3_clear_uie(vcpu);
 }
 
 static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
@@ -642,7 +642,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	if (unlikely(!vgic_initialized(vcpu->kvm)))
 		return;
 
-	vgic_process_maintenance_interrupt(vcpu);
+	vgic_clear_uie(vcpu);
 	vgic_fold_lr_state(vcpu);
 	vgic_prune_ap_list(vcpu);
 
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 3f64220..72ba9ee 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -112,7 +112,7 @@ void vgic_kick_vcpus(struct kvm *kvm);
 int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
 		      phys_addr_t addr, phys_addr_t alignment);
 
-void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v2_clear_uie(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);
@@ -143,7 +143,7 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
 	kref_get(&irq->refcount);
 }
 
-void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v3_clear_uie(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);
-- 
2.9.0

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

* [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operation
@ 2017-03-20 10:58   ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

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

Since we always read back the LRs that we wrote to the guest and the
MISR and EISR registers simply provide a summary of the configuration of
the bits in the LRs, there is really no need to read back those status
registers and process them.  We can might as well just signal the
notifyfd when folding the LR state and save some cycles in the process.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/vgic/vgic-v2.c | 55 ++++++++++-----------------------------------
 virt/kvm/arm/vgic/vgic-v3.c | 47 +++++++++++---------------------------
 virt/kvm/arm/vgic/vgic.c    |  8 +++----
 virt/kvm/arm/vgic/vgic.h    |  4 ++--
 4 files changed, 31 insertions(+), 83 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index dfe6e5e..0172754 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -22,20 +22,6 @@
 
 #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;
-}
-
 static inline void vgic_v2_write_lr(int lr, u32 val)
 {
 	void __iomem *base = kvm_vgic_global_state.vctrl_base;
@@ -51,38 +37,10 @@ void vgic_v2_init_lrs(void)
 		vgic_v2_write_lr(i, 0);
 }
 
-void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
+void vgic_v2_clear_uie(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);
-
-			/* Only SPIs require notification */
-			if (vgic_valid_spi(vcpu->kvm, intid))
-				kvm_notify_acked_irq(vcpu->kvm, 0,
-						     intid - VGIC_NR_PRIVATE_IRQS);
-		}
-	}
-
-	/* 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)
@@ -92,6 +50,12 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
 	cpuif->vgic_hcr |= GICH_HCR_UIE;
 }
 
+static bool lr_signals_eoi_mi(u32 lr_val)
+{
+	return !(lr_val & GICH_LR_STATE) && (lr_val & GICH_LR_EOI) &&
+	       !(lr_val & GICH_LR_HW);
+}
+
 /*
  * transfer the content of the LRs back into the corresponding ap_list:
  * - active bit is transferred as is
@@ -109,6 +73,11 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
 		u32 intid = val & GICH_LR_VIRTUALID;
 		struct vgic_irq *irq;
 
+		/* Notify fds when the guest EOI'ed a level-triggered SPI */
+		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
 		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
 
 		spin_lock(&irq->irq_lock);
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 3d7796c..7880c5c 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -21,42 +21,9 @@
 
 #include "vgic.h"
 
-void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
+void vgic_v3_clear_uie(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);
-
-			/* Only SPIs require notification */
-			if (vgic_valid_spi(vcpu->kvm, intid))
-				kvm_notify_acked_irq(vcpu->kvm, 0,
-						     intid - VGIC_NR_PRIVATE_IRQS);
-		}
-
-		/*
-		 * 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;
 }
 
@@ -67,6 +34,12 @@ void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 	cpuif->vgic_hcr |= ICH_HCR_UIE;
 }
 
+static bool lr_signals_eoi_mi(u64 lr_val)
+{
+	return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) &&
+	       !(lr_val & ICH_LR_HW);
+}
+
 void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -82,6 +55,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 			intid = val & ICH_LR_VIRTUAL_ID_MASK;
 		else
 			intid = val & GICH_LR_VIRTUALID;
+
+		/* Notify fds when the guest EOI'ed a level-triggered IRQ */
+		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
 		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
 		if (!irq)	/* An LPI could have been unmapped. */
 			continue;
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 1436c2e..f5b3c25 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -527,12 +527,12 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
 	spin_unlock(&vgic_cpu->ap_list_lock);
 }
 
-static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
+static inline void vgic_clear_uie(struct kvm_vcpu *vcpu)
 {
 	if (kvm_vgic_global_state.type == VGIC_V2)
-		vgic_v2_process_maintenance(vcpu);
+		vgic_v2_clear_uie(vcpu);
 	else
-		vgic_v3_process_maintenance(vcpu);
+		vgic_v3_clear_uie(vcpu);
 }
 
 static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
@@ -642,7 +642,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	if (unlikely(!vgic_initialized(vcpu->kvm)))
 		return;
 
-	vgic_process_maintenance_interrupt(vcpu);
+	vgic_clear_uie(vcpu);
 	vgic_fold_lr_state(vcpu);
 	vgic_prune_ap_list(vcpu);
 
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 3f64220..72ba9ee 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -112,7 +112,7 @@ void vgic_kick_vcpus(struct kvm *kvm);
 int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
 		      phys_addr_t addr, phys_addr_t alignment);
 
-void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v2_clear_uie(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);
@@ -143,7 +143,7 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
 	kref_get(&irq->refcount);
 }
 
-void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v3_clear_uie(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);
-- 
2.9.0

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

* [PATCH 5/9] KVM: arm/arm64: vgic: Get rid of unnecessary save_maint_int_state
  2017-03-20 10:58 ` Christoffer Dall
@ 2017-03-20 10:58   ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

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

Now when we don't look at the MISR and EISR values anymore, we can get
rid of the logic to save them in the GIC save/restore code.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/hyp/vgic-v2-sr.c | 40 ----------------------------------------
 virt/kvm/arm/hyp/vgic-v3-sr.c | 29 -----------------------------
 2 files changed, 69 deletions(-)

diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 34b37ce..a4c3bb0 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -22,45 +22,6 @@
 #include <asm/kvm_emulate.h>
 #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;
-	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-	u32 eisr0, eisr1;
-	int i;
-	bool expect_mi;
-
-	expect_mi = !!(cpu_if->vgic_hcr & GICH_HCR_UIE);
-
-	for (i = 0; i < used_lrs && !expect_mi; i++)
-		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(used_lrs > 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
-}
-
 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;
@@ -111,7 +72,6 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
 	if (used_lrs) {
 		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
 
-		save_maint_int_state(vcpu, base);
 		save_elrsr(vcpu, base);
 		save_lrs(vcpu, base);
 
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index b3c36b6..41bbbb0 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -118,33 +118,6 @@ static void __hyp_text __gic_v3_set_lr(u64 val, int lr)
 	}
 }
 
-static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu)
-{
-	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
-	int i;
-	bool expect_mi;
-	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-
-	expect_mi = !!(cpu_if->vgic_hcr & ICH_HCR_UIE);
-
-	for (i = 0; i < used_lrs; i++) {
-		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;
@@ -168,8 +141,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 		val = read_gicreg(ICH_VTR_EL2);
 		nr_pri_bits = vtr_to_nr_pri_bits(val);
 
-		save_maint_int_state(vcpu);
-
 		for (i = 0; i <= used_lrs; i++) {
 			if (cpu_if->vgic_elrsr & (1 << i))
 				cpu_if->vgic_lr[i] &= ~ICH_LR_STATE;
-- 
2.9.0

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

* [PATCH 5/9] KVM: arm/arm64: vgic: Get rid of unnecessary save_maint_int_state
@ 2017-03-20 10:58   ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

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

Now when we don't look at the MISR and EISR values anymore, we can get
rid of the logic to save them in the GIC save/restore code.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/hyp/vgic-v2-sr.c | 40 ----------------------------------------
 virt/kvm/arm/hyp/vgic-v3-sr.c | 29 -----------------------------
 2 files changed, 69 deletions(-)

diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 34b37ce..a4c3bb0 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -22,45 +22,6 @@
 #include <asm/kvm_emulate.h>
 #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;
-	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-	u32 eisr0, eisr1;
-	int i;
-	bool expect_mi;
-
-	expect_mi = !!(cpu_if->vgic_hcr & GICH_HCR_UIE);
-
-	for (i = 0; i < used_lrs && !expect_mi; i++)
-		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(used_lrs > 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
-}
-
 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;
@@ -111,7 +72,6 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
 	if (used_lrs) {
 		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
 
-		save_maint_int_state(vcpu, base);
 		save_elrsr(vcpu, base);
 		save_lrs(vcpu, base);
 
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index b3c36b6..41bbbb0 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -118,33 +118,6 @@ static void __hyp_text __gic_v3_set_lr(u64 val, int lr)
 	}
 }
 
-static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu)
-{
-	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
-	int i;
-	bool expect_mi;
-	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-
-	expect_mi = !!(cpu_if->vgic_hcr & ICH_HCR_UIE);
-
-	for (i = 0; i < used_lrs; i++) {
-		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;
@@ -168,8 +141,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 		val = read_gicreg(ICH_VTR_EL2);
 		nr_pri_bits = vtr_to_nr_pri_bits(val);
 
-		save_maint_int_state(vcpu);
-
 		for (i = 0; i <= used_lrs; i++) {
 			if (cpu_if->vgic_elrsr & (1 << i))
 				cpu_if->vgic_lr[i] &= ~ICH_LR_STATE;
-- 
2.9.0

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

* [PATCH 6/9] KVM: arm/arm64: vgic: Get rid of MISR and EISR fields
  2017-03-20 10:58 ` Christoffer Dall
@ 2017-03-20 10:58   ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Andre Przywara, kvm

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

We don't use these fields anymore so let's nuke them completely.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 include/kvm/arm_vgic.h        | 4 ----
 virt/kvm/arm/hyp/vgic-v2-sr.c | 2 --
 virt/kvm/arm/hyp/vgic-v3-sr.c | 2 --
 3 files changed, 8 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index fa12d99..581a59e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -225,8 +225,6 @@ struct vgic_dist {
 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];
@@ -236,8 +234,6 @@ struct vgic_v3_cpu_if {
 	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];
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index a4c3bb0..a3f18d3 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -77,9 +77,7 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
 
 		writel_relaxed(0, base + GICH_HCR);
 	} else {
-		cpu_if->vgic_eisr = 0;
 		cpu_if->vgic_elrsr = ~0UL;
-		cpu_if->vgic_misr = 0;
 		cpu_if->vgic_apr = 0;
 	}
 }
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 41bbbb0..3d0b1dd 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -170,8 +170,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 			cpu_if->vgic_ap1r[0] = read_gicreg(ICH_AP1R0_EL2);
 		}
 	} 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;
-- 
2.9.0

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

* [PATCH 6/9] KVM: arm/arm64: vgic: Get rid of MISR and EISR fields
@ 2017-03-20 10:58   ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

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

We don't use these fields anymore so let's nuke them completely.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 include/kvm/arm_vgic.h        | 4 ----
 virt/kvm/arm/hyp/vgic-v2-sr.c | 2 --
 virt/kvm/arm/hyp/vgic-v3-sr.c | 2 --
 3 files changed, 8 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index fa12d99..581a59e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -225,8 +225,6 @@ struct vgic_dist {
 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];
@@ -236,8 +234,6 @@ struct vgic_v3_cpu_if {
 	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];
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index a4c3bb0..a3f18d3 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -77,9 +77,7 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
 
 		writel_relaxed(0, base + GICH_HCR);
 	} else {
-		cpu_if->vgic_eisr = 0;
 		cpu_if->vgic_elrsr = ~0UL;
-		cpu_if->vgic_misr = 0;
 		cpu_if->vgic_apr = 0;
 	}
 }
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 41bbbb0..3d0b1dd 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -170,8 +170,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 			cpu_if->vgic_ap1r[0] = read_gicreg(ICH_AP1R0_EL2);
 		}
 	} 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;
-- 
2.9.0

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

* [PATCH 7/9] KVM: arm/arm64: vgic: Implement early VGIC init functionality
  2017-03-20 10:58 ` Christoffer Dall
@ 2017-03-20 10:58   ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Marc Zyngier, Andre Przywara, Christoffer Dall, kvm

Implement early initialization for both the distributor and the CPU
interfaces.  The basic idea is that even though the VGIC is not
functional or not requested from user space, the critical path of the
run loop can still call VGIC functions that just won't do anything,
without them having to check additional initialization flags to ensure
they don't look at uninitialized data structures.

Signed-off-by: Christoffer Dall <cdall@linaro.org>
---
 virt/kvm/arm/vgic/vgic-init.c | 96 +++++++++++++++++++++++++------------------
 1 file changed, 56 insertions(+), 40 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 3762fd1..25fd1b9 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -24,7 +24,12 @@
 
 /*
  * Initialization rules: there are multiple stages to the vgic
- * initialization, both for the distributor and the CPU interfaces.
+ * initialization, both for the distributor and the CPU interfaces.  The basic
+ * idea is that even though the VGIC is not functional or not requested from
+ * user space, the critical path of the run loop can still call VGIC functions
+ * that just won't do anything, without them having to check additional
+ * initialization flags to ensure they don't look at uninitialized data
+ * structures.
  *
  * Distributor:
  *
@@ -39,23 +44,67 @@
  *
  * CPU Interface:
  *
- * - kvm_vgic_cpu_early_init(): initialization of static data that
+ * - kvm_vgic_vcpu_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
+/**
+ * kvm_vgic_early_init() - Initialize static VGIC VCPU data structures
+ * @kvm: The VM whose VGIC districutor should be initialized
+ *
+ * Only do initialization of static structures that don't require any
+ * allocation or sizing information from userspace.  vgic_init() called
+ * kvm_vgic_dist_init() which takes care of the rest.
  */
 void kvm_vgic_early_init(struct kvm *kvm)
 {
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	INIT_LIST_HEAD(&dist->lpi_list_head);
+	spin_lock_init(&dist->lpi_list_lock);
 }
 
+/**
+ * kvm_vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
+ * @vcpu: The VCPU whose VGIC data structures whould be initialized
+ *
+ * Only do initialization, but do not actually enable the VGIC CPU interface
+ * yet.
+ */
 void kvm_vgic_vcpu_early_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;
+		kref_init(&irq->refcount);
+		if (vgic_irq_is_sgi(i)) {
+			/* SGIs */
+			irq->enabled = 1;
+			irq->config = VGIC_CONFIG_EDGE;
+		} else {
+			/* PPIs */
+			irq->config = VGIC_CONFIG_LEVEL;
+		}
+	}
 }
 
 /* CREATION */
@@ -148,9 +197,6 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
 	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
 	int i;
 
-	INIT_LIST_HEAD(&dist->lpi_list_head);
-	spin_lock_init(&dist->lpi_list_lock);
-
 	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
 	if (!dist->spis)
 		return  -ENOMEM;
@@ -181,41 +227,11 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
 }
 
 /**
- * kvm_vgic_vcpu_init: initialize the vcpu data structures and
- * enable the VCPU interface
- * @vcpu: the VCPU which's VGIC should be initialized
+ * kvm_vgic_vcpu_init() - Enable the VCPU interface
+ * @vcpu: the VCPU which's VGIC should be enabled
  */
 static 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;
-		kref_init(&irq->refcount);
-		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
-- 
2.9.0

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

* [PATCH 7/9] KVM: arm/arm64: vgic: Implement early VGIC init functionality
@ 2017-03-20 10:58   ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

Implement early initialization for both the distributor and the CPU
interfaces.  The basic idea is that even though the VGIC is not
functional or not requested from user space, the critical path of the
run loop can still call VGIC functions that just won't do anything,
without them having to check additional initialization flags to ensure
they don't look at uninitialized data structures.

Signed-off-by: Christoffer Dall <cdall@linaro.org>
---
 virt/kvm/arm/vgic/vgic-init.c | 96 +++++++++++++++++++++++++------------------
 1 file changed, 56 insertions(+), 40 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 3762fd1..25fd1b9 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -24,7 +24,12 @@
 
 /*
  * Initialization rules: there are multiple stages to the vgic
- * initialization, both for the distributor and the CPU interfaces.
+ * initialization, both for the distributor and the CPU interfaces.  The basic
+ * idea is that even though the VGIC is not functional or not requested from
+ * user space, the critical path of the run loop can still call VGIC functions
+ * that just won't do anything, without them having to check additional
+ * initialization flags to ensure they don't look at uninitialized data
+ * structures.
  *
  * Distributor:
  *
@@ -39,23 +44,67 @@
  *
  * CPU Interface:
  *
- * - kvm_vgic_cpu_early_init(): initialization of static data that
+ * - kvm_vgic_vcpu_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
+/**
+ * kvm_vgic_early_init() - Initialize static VGIC VCPU data structures
+ * @kvm: The VM whose VGIC districutor should be initialized
+ *
+ * Only do initialization of static structures that don't require any
+ * allocation or sizing information from userspace.  vgic_init() called
+ * kvm_vgic_dist_init() which takes care of the rest.
  */
 void kvm_vgic_early_init(struct kvm *kvm)
 {
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	INIT_LIST_HEAD(&dist->lpi_list_head);
+	spin_lock_init(&dist->lpi_list_lock);
 }
 
+/**
+ * kvm_vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
+ * @vcpu: The VCPU whose VGIC data structures whould be initialized
+ *
+ * Only do initialization, but do not actually enable the VGIC CPU interface
+ * yet.
+ */
 void kvm_vgic_vcpu_early_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;
+		kref_init(&irq->refcount);
+		if (vgic_irq_is_sgi(i)) {
+			/* SGIs */
+			irq->enabled = 1;
+			irq->config = VGIC_CONFIG_EDGE;
+		} else {
+			/* PPIs */
+			irq->config = VGIC_CONFIG_LEVEL;
+		}
+	}
 }
 
 /* CREATION */
@@ -148,9 +197,6 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
 	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
 	int i;
 
-	INIT_LIST_HEAD(&dist->lpi_list_head);
-	spin_lock_init(&dist->lpi_list_lock);
-
 	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
 	if (!dist->spis)
 		return  -ENOMEM;
@@ -181,41 +227,11 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
 }
 
 /**
- * kvm_vgic_vcpu_init: initialize the vcpu data structures and
- * enable the VCPU interface
- * @vcpu: the VCPU which's VGIC should be initialized
+ * kvm_vgic_vcpu_init() - Enable the VCPU interface
+ * @vcpu: the VCPU which's VGIC should be enabled
  */
 static 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;
-		kref_init(&irq->refcount);
-		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
-- 
2.9.0

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

* [PATCH 8/9] KVM: arm/arm64: vgic: Don't check vgic_initialized in flush_hwstate
  2017-03-20 10:58 ` Christoffer Dall
@ 2017-03-20 10:58   ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Marc Zyngier, Andre Przywara, Christoffer Dall, kvm

Now when we do an early init of the static parts of the VGIC data
structures, we can do things like checking if the AP lists are empty
directly without having to explicitly check if the vgic is initialized
and reduce a bit of work in our criticial path.

Note: list_empty is a single atomic read (uses READ_ONCE) and can
therefore check if a list is empty or not without the need to take the
spinlock protecting the list.

Signed-off-by: Christoffer Dall <cdall@linaro.org>
---
 virt/kvm/arm/vgic/vgic.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index f5b3c25..093873e 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -653,9 +653,6 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 /* Flush our emulation state into the GIC hardware before entering the guest. */
 void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
-		return;
-
 	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
 		return;
 
-- 
2.9.0

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

* [PATCH 8/9] KVM: arm/arm64: vgic: Don't check vgic_initialized in flush_hwstate
@ 2017-03-20 10:58   ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

Now when we do an early init of the static parts of the VGIC data
structures, we can do things like checking if the AP lists are empty
directly without having to explicitly check if the vgic is initialized
and reduce a bit of work in our criticial path.

Note: list_empty is a single atomic read (uses READ_ONCE) and can
therefore check if a list is empty or not without the need to take the
spinlock protecting the list.

Signed-off-by: Christoffer Dall <cdall@linaro.org>
---
 virt/kvm/arm/vgic/vgic.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index f5b3c25..093873e 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -653,9 +653,6 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 /* Flush our emulation state into the GIC hardware before entering the guest. */
 void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
-		return;
-
 	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
 		return;
 
-- 
2.9.0

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

* [PATCH 9/9] KVM: arm/arm64: vgic: Improve sync_hwstate performance
  2017-03-20 10:58 ` Christoffer Dall
@ 2017-03-20 10:58   ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Marc Zyngier, Andre Przywara, Christoffer Dall, kvm

There is no need to call any functions to fold LRs when we don't use any
LRs and we don't need to mess with overflow flags, take spinlocks, or
prune the AP list if the AP list is empty.

Note: list_empty is a single atomic read (uses READ_ONCE) and can
therefore check if a list is empty or not without the need to take the
spinlock protecting the list.

Signed-off-by: Christoffer Dall <cdall@linaro.org>
---
 virt/kvm/arm/vgic/vgic.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 093873e..8ecb009 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -639,15 +639,18 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
+	/* An empty ap_list_head implies used_lrs == 0 */
+	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
 		return;
 
 	vgic_clear_uie(vcpu);
-	vgic_fold_lr_state(vcpu);
-	vgic_prune_ap_list(vcpu);
 
-	/* Make sure we can fast-path in flush_hwstate */
-	vgic_cpu->used_lrs = 0;
+	if (vgic_cpu->used_lrs) {
+		vgic_fold_lr_state(vcpu);
+		vgic_cpu->used_lrs = 0;
+	}
+
+	vgic_prune_ap_list(vcpu);
 }
 
 /* Flush our emulation state into the GIC hardware before entering the guest. */
-- 
2.9.0

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

* [PATCH 9/9] KVM: arm/arm64: vgic: Improve sync_hwstate performance
@ 2017-03-20 10:58   ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-20 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

There is no need to call any functions to fold LRs when we don't use any
LRs and we don't need to mess with overflow flags, take spinlocks, or
prune the AP list if the AP list is empty.

Note: list_empty is a single atomic read (uses READ_ONCE) and can
therefore check if a list is empty or not without the need to take the
spinlock protecting the list.

Signed-off-by: Christoffer Dall <cdall@linaro.org>
---
 virt/kvm/arm/vgic/vgic.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 093873e..8ecb009 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -639,15 +639,18 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
+	/* An empty ap_list_head implies used_lrs == 0 */
+	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
 		return;
 
 	vgic_clear_uie(vcpu);
-	vgic_fold_lr_state(vcpu);
-	vgic_prune_ap_list(vcpu);
 
-	/* Make sure we can fast-path in flush_hwstate */
-	vgic_cpu->used_lrs = 0;
+	if (vgic_cpu->used_lrs) {
+		vgic_fold_lr_state(vcpu);
+		vgic_cpu->used_lrs = 0;
+	}
+
+	vgic_prune_ap_list(vcpu);
 }
 
 /* Flush our emulation state into the GIC hardware before entering the guest. */
-- 
2.9.0

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

* Re: [PATCH 1/9] KVM: arm/arm64: vgic: Defer touching GICH_VMCR to vcpu_load/put
  2017-03-20 10:58   ` Christoffer Dall
@ 2017-03-21 10:29     ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 10:29 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Andre Przywara, Christoffer Dall, kvm

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> We don't have to save/restore the VMCR on every entry to/from the guest,
> since on GICv2 we can access the control interface from EL1 and on VHE
> systems with GICv3 we can access the control interface from KVM running
> in EL2.
> 
> GICv3 systems without VHE becomes the rare case, which has to
> save/restore the register on each round trip.
> 
> For in-context accesses to the VMCR, meaning emulation code needs access
> to the value of the VCPU that is currently running within vcpu_load
> and vcpu_put will detect that the it should load the VMCR from the
> physical GIC instead of using the cached memory value.  While this extra
> checking adds some code complexity we end up moving code out of the
> critical path.
> 
> Note that userspace accesses may see out-of-date values if the VCPU is
> running while accessing the VGIC state via the KVM device API, but this
> is already the case.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> Signed-off-by: Christoffer Dall <cdall@linaro.org>
> ---
>  arch/arm/include/asm/kvm_asm.h   |  3 +++
>  arch/arm/kvm/arm.c               | 11 +++++-----
>  arch/arm64/include/asm/kvm_asm.h |  2 ++
>  include/kvm/arm_vgic.h           |  3 +++
>  virt/kvm/arm/hyp/vgic-v2-sr.c    |  3 ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c    | 14 ++++++++----
>  virt/kvm/arm/vgic/vgic-init.c    | 12 +++++++++++
>  virt/kvm/arm/vgic/vgic-v2.c      | 46 ++++++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic-v3.c      | 42 ++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic.c         | 22 +++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h         |  6 ++++++
>  11 files changed, 148 insertions(+), 16 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
> index 8ef0538..dd16044 100644
> --- a/arch/arm/include/asm/kvm_asm.h
> +++ b/arch/arm/include/asm/kvm_asm.h
> @@ -75,7 +75,10 @@ extern void __init_stage2_translation(void);
>  extern void __kvm_hyp_reset(unsigned long);
>  
>  extern u64 __vgic_v3_get_ich_vtr_el2(void);
> +extern u64 __vgic_v3_read_vmcr(void);
> +extern void __vgic_v3_write_vmcr(u32 vmcr);
>  extern void __vgic_v3_init_lrs(void);
> +
>  #endif
>  
>  #endif /* __ARM_KVM_ASM_H__ */
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index d775aac..cfdf2f5 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -348,15 +348,14 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>  	vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
>  
>  	kvm_arm_set_running_vcpu(vcpu);
> +
> +	kvm_vgic_load(vcpu);
>  }
>  
>  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
>  {
> -	/*
> -	 * The arch-generic KVM code expects the cpu field of a vcpu to be -1
> -	 * if the vcpu is no longer assigned to a cpu.  This is used for the
> -	 * optimized make_all_cpus_request path.
> -	 */
> +	kvm_vgic_put(vcpu);
> +
>  	vcpu->cpu = -1;
>  
>  	kvm_arm_set_running_vcpu(NULL);
> @@ -630,7 +629,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		 * non-preemptible context.
>  		 */
>  		preempt_disable();
> +
>  		kvm_pmu_flush_hwstate(vcpu);
> +
>  		kvm_timer_flush_hwstate(vcpu);
>  		kvm_vgic_flush_hwstate(vcpu);
>  
> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> index ec3553eb..49f99cd 100644
> --- a/arch/arm64/include/asm/kvm_asm.h
> +++ b/arch/arm64/include/asm/kvm_asm.h
> @@ -59,6 +59,8 @@ extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
>  extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
>  
>  extern u64 __vgic_v3_get_ich_vtr_el2(void);
> +extern u64 __vgic_v3_read_vmcr(void);
> +extern void __vgic_v3_write_vmcr(u32 vmcr);
>  extern void __vgic_v3_init_lrs(void);
>  
>  extern u32 __kvm_get_mdcr_el2(void);
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index c0b3d99..8d7c3a7 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -307,6 +307,9 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>  
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  
> +void kvm_vgic_load(struct kvm_vcpu *vcpu);
> +void kvm_vgic_put(struct kvm_vcpu *vcpu);
> +
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	((k)->arch.vgic.initialized)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
> index c8aeb7b..d3d3b9b 100644
> --- a/virt/kvm/arm/hyp/vgic-v2-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
> @@ -114,8 +114,6 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
>  	if (!base)
>  		return;
>  
> -	cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
> -
>  	if (vcpu->arch.vgic_cpu.live_lrs) {
>  		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
>  
> @@ -165,7 +163,6 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
>  		}
>  	}
>  
> -	writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
>  	vcpu->arch.vgic_cpu.live_lrs = live_lrs;
>  }
>  
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 3947095..e51ee7e 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -159,8 +159,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
>  	if (!cpu_if->vgic_sre)
>  		dsb(st);
>  
> -	cpu_if->vgic_vmcr  = read_gicreg(ICH_VMCR_EL2);
> -
>  	if (vcpu->arch.vgic_cpu.live_lrs) {
>  		int i;
>  		u32 max_lr_idx, nr_pri_bits;
> @@ -261,8 +259,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  			live_lrs |= (1 << i);
>  	}
>  
> -	write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
> -
>  	if (live_lrs) {
>  		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
>  
> @@ -326,3 +322,13 @@ u64 __hyp_text __vgic_v3_get_ich_vtr_el2(void)
>  {
>  	return read_gicreg(ICH_VTR_EL2);
>  }
> +
> +u64 __hyp_text __vgic_v3_read_vmcr(void)
> +{
> +	return read_gicreg(ICH_VMCR_EL2);
> +}
> +
> +void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> +{
> +	write_gicreg(vmcr, ICH_VMCR_EL2);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index 702f810..3762fd1 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -262,6 +262,18 @@ int vgic_init(struct kvm *kvm)
>  	vgic_debug_init(kvm);
>  
>  	dist->initialized = true;
> +
> +	/*
> +	 * If we're initializing GICv2 on-demand when first running the VCPU
> +	 * then we need to load the VGIC state onto the CPU.  We can detect
> +	 * this easily by checking if we are in between vcpu_load and vcpu_put
> +	 * when we just initialized the VGIC.
> +	 */
> +	preempt_disable();
> +	vcpu = kvm_arm_get_running_vcpu();
> +	if (vcpu)
> +		kvm_vgic_load(vcpu);
> +	preempt_enable();
>  out:
>  	return ret;
>  }
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 94cf4b9..dfe6e5e 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -199,6 +199,9 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  
>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  {
> +	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> +	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int cpu;
>  	u32 vmcr;
>  
>  	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
> @@ -209,12 +212,35 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
>  		GICH_VMCR_PRIMASK_MASK;
>  
> -	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
> +	cpu_if->vgic_vmcr = vmcr;
> +
> +	cpu = get_cpu();
> +	if (vcpu->cpu == cpu)
> +		/*
> +		 * We have run vcpu_load and we're on VHE which means the VMCR
> +		 * has already been flushed to the CPU; flush it again.
> +		 */

I don't understand this comment. What has VHE to do with this?

> +		writel_relaxed(vmcr, vgic->vctrl_base + GICH_VMCR);
> +	put_cpu();

There is one thing I don't quite get: I thought we could only get there
with a userspace access. I understand that we've run vcpu_load()
already, and that we end-up with a stale configuration in the HW. But
why do we need to immediately propagate it? Surely we can rely on the
vcpu thread doing a vcpu_load itself to load the new value, right? I
must be missing something...

>  }
>  
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  {
> -	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
> +	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> +	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int cpu;
> +	u32 vmcr;
> +
> +	cpu = get_cpu();
> +	if (vcpu->cpu == cpu)
> +		/*
> +		 * We have run vcpu_load and which means the VMCR
> +		 * has already been flushed to the CPU; sync it back.
> +		 */
> +		cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
> +	put_cpu();
> +
> +	vmcr = cpu_if->vgic_vmcr;

Same comment as above.

Thanks,

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

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

* [PATCH 1/9] KVM: arm/arm64: vgic: Defer touching GICH_VMCR to vcpu_load/put
@ 2017-03-21 10:29     ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 10:29 UTC (permalink / raw)
  To: linux-arm-kernel

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> We don't have to save/restore the VMCR on every entry to/from the guest,
> since on GICv2 we can access the control interface from EL1 and on VHE
> systems with GICv3 we can access the control interface from KVM running
> in EL2.
> 
> GICv3 systems without VHE becomes the rare case, which has to
> save/restore the register on each round trip.
> 
> For in-context accesses to the VMCR, meaning emulation code needs access
> to the value of the VCPU that is currently running within vcpu_load
> and vcpu_put will detect that the it should load the VMCR from the
> physical GIC instead of using the cached memory value.  While this extra
> checking adds some code complexity we end up moving code out of the
> critical path.
> 
> Note that userspace accesses may see out-of-date values if the VCPU is
> running while accessing the VGIC state via the KVM device API, but this
> is already the case.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> Signed-off-by: Christoffer Dall <cdall@linaro.org>
> ---
>  arch/arm/include/asm/kvm_asm.h   |  3 +++
>  arch/arm/kvm/arm.c               | 11 +++++-----
>  arch/arm64/include/asm/kvm_asm.h |  2 ++
>  include/kvm/arm_vgic.h           |  3 +++
>  virt/kvm/arm/hyp/vgic-v2-sr.c    |  3 ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c    | 14 ++++++++----
>  virt/kvm/arm/vgic/vgic-init.c    | 12 +++++++++++
>  virt/kvm/arm/vgic/vgic-v2.c      | 46 ++++++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic-v3.c      | 42 ++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic.c         | 22 +++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h         |  6 ++++++
>  11 files changed, 148 insertions(+), 16 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
> index 8ef0538..dd16044 100644
> --- a/arch/arm/include/asm/kvm_asm.h
> +++ b/arch/arm/include/asm/kvm_asm.h
> @@ -75,7 +75,10 @@ extern void __init_stage2_translation(void);
>  extern void __kvm_hyp_reset(unsigned long);
>  
>  extern u64 __vgic_v3_get_ich_vtr_el2(void);
> +extern u64 __vgic_v3_read_vmcr(void);
> +extern void __vgic_v3_write_vmcr(u32 vmcr);
>  extern void __vgic_v3_init_lrs(void);
> +
>  #endif
>  
>  #endif /* __ARM_KVM_ASM_H__ */
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index d775aac..cfdf2f5 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -348,15 +348,14 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>  	vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
>  
>  	kvm_arm_set_running_vcpu(vcpu);
> +
> +	kvm_vgic_load(vcpu);
>  }
>  
>  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
>  {
> -	/*
> -	 * The arch-generic KVM code expects the cpu field of a vcpu to be -1
> -	 * if the vcpu is no longer assigned to a cpu.  This is used for the
> -	 * optimized make_all_cpus_request path.
> -	 */
> +	kvm_vgic_put(vcpu);
> +
>  	vcpu->cpu = -1;
>  
>  	kvm_arm_set_running_vcpu(NULL);
> @@ -630,7 +629,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		 * non-preemptible context.
>  		 */
>  		preempt_disable();
> +
>  		kvm_pmu_flush_hwstate(vcpu);
> +
>  		kvm_timer_flush_hwstate(vcpu);
>  		kvm_vgic_flush_hwstate(vcpu);
>  
> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> index ec3553eb..49f99cd 100644
> --- a/arch/arm64/include/asm/kvm_asm.h
> +++ b/arch/arm64/include/asm/kvm_asm.h
> @@ -59,6 +59,8 @@ extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
>  extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
>  
>  extern u64 __vgic_v3_get_ich_vtr_el2(void);
> +extern u64 __vgic_v3_read_vmcr(void);
> +extern void __vgic_v3_write_vmcr(u32 vmcr);
>  extern void __vgic_v3_init_lrs(void);
>  
>  extern u32 __kvm_get_mdcr_el2(void);
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index c0b3d99..8d7c3a7 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -307,6 +307,9 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>  
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  
> +void kvm_vgic_load(struct kvm_vcpu *vcpu);
> +void kvm_vgic_put(struct kvm_vcpu *vcpu);
> +
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	((k)->arch.vgic.initialized)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
> index c8aeb7b..d3d3b9b 100644
> --- a/virt/kvm/arm/hyp/vgic-v2-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
> @@ -114,8 +114,6 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
>  	if (!base)
>  		return;
>  
> -	cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
> -
>  	if (vcpu->arch.vgic_cpu.live_lrs) {
>  		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
>  
> @@ -165,7 +163,6 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
>  		}
>  	}
>  
> -	writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
>  	vcpu->arch.vgic_cpu.live_lrs = live_lrs;
>  }
>  
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 3947095..e51ee7e 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -159,8 +159,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
>  	if (!cpu_if->vgic_sre)
>  		dsb(st);
>  
> -	cpu_if->vgic_vmcr  = read_gicreg(ICH_VMCR_EL2);
> -
>  	if (vcpu->arch.vgic_cpu.live_lrs) {
>  		int i;
>  		u32 max_lr_idx, nr_pri_bits;
> @@ -261,8 +259,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  			live_lrs |= (1 << i);
>  	}
>  
> -	write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
> -
>  	if (live_lrs) {
>  		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
>  
> @@ -326,3 +322,13 @@ u64 __hyp_text __vgic_v3_get_ich_vtr_el2(void)
>  {
>  	return read_gicreg(ICH_VTR_EL2);
>  }
> +
> +u64 __hyp_text __vgic_v3_read_vmcr(void)
> +{
> +	return read_gicreg(ICH_VMCR_EL2);
> +}
> +
> +void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> +{
> +	write_gicreg(vmcr, ICH_VMCR_EL2);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index 702f810..3762fd1 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -262,6 +262,18 @@ int vgic_init(struct kvm *kvm)
>  	vgic_debug_init(kvm);
>  
>  	dist->initialized = true;
> +
> +	/*
> +	 * If we're initializing GICv2 on-demand when first running the VCPU
> +	 * then we need to load the VGIC state onto the CPU.  We can detect
> +	 * this easily by checking if we are in between vcpu_load and vcpu_put
> +	 * when we just initialized the VGIC.
> +	 */
> +	preempt_disable();
> +	vcpu = kvm_arm_get_running_vcpu();
> +	if (vcpu)
> +		kvm_vgic_load(vcpu);
> +	preempt_enable();
>  out:
>  	return ret;
>  }
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 94cf4b9..dfe6e5e 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -199,6 +199,9 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  
>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  {
> +	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> +	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int cpu;
>  	u32 vmcr;
>  
>  	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
> @@ -209,12 +212,35 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
>  		GICH_VMCR_PRIMASK_MASK;
>  
> -	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
> +	cpu_if->vgic_vmcr = vmcr;
> +
> +	cpu = get_cpu();
> +	if (vcpu->cpu == cpu)
> +		/*
> +		 * We have run vcpu_load and we're on VHE which means the VMCR
> +		 * has already been flushed to the CPU; flush it again.
> +		 */

I don't understand this comment. What has VHE to do with this?

> +		writel_relaxed(vmcr, vgic->vctrl_base + GICH_VMCR);
> +	put_cpu();

There is one thing I don't quite get: I thought we could only get there
with a userspace access. I understand that we've run vcpu_load()
already, and that we end-up with a stale configuration in the HW. But
why do we need to immediately propagate it? Surely we can rely on the
vcpu thread doing a vcpu_load itself to load the new value, right? I
must be missing something...

>  }
>  
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  {
> -	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
> +	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> +	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int cpu;
> +	u32 vmcr;
> +
> +	cpu = get_cpu();
> +	if (vcpu->cpu == cpu)
> +		/*
> +		 * We have run vcpu_load and which means the VMCR
> +		 * has already been flushed to the CPU; sync it back.
> +		 */
> +		cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
> +	put_cpu();
> +
> +	vmcr = cpu_if->vgic_vmcr;

Same comment as above.

Thanks,

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

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

* Re: [PATCH 2/9] KVM: arm/arm64: vgic: Avoid flushing vgic state when there's no pending IRQ
  2017-03-20 10:58   ` Christoffer Dall
@ 2017-03-21 10:57     ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 10:57 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: kvm, Andre Przywara, Eric Auger, Shih-Wei Li

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Shih-Wei Li <shihwei@cs.columbia.edu>
> 
> We do not need to flush vgic states in each world switch unless
> there is pending IRQ queued to the vgic's ap list. We can thus reduce
> the overhead by not grabbing the spinlock and not making the extra
> function call to vgic_flush_lr_state.
> 
> Signed-off-by: Shih-Wei Li <shihwei@cs.columbia.edu>
> Signed-off-by: Christoffer Dall <cdall@linaro.org>
> ---
>  virt/kvm/arm/vgic/vgic.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 2ac0def..1436c2e 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -637,12 +637,17 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
>  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
>  void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>  {
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +
>  	if (unlikely(!vgic_initialized(vcpu->kvm)))
>  		return;
>  
>  	vgic_process_maintenance_interrupt(vcpu);
>  	vgic_fold_lr_state(vcpu);
>  	vgic_prune_ap_list(vcpu);
> +
> +	/* Make sure we can fast-path in flush_hwstate */
> +	vgic_cpu->used_lrs = 0;
>  }
>  
>  /* Flush our emulation state into the GIC hardware before entering the guest. */
> @@ -651,6 +656,9 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>  	if (unlikely(!vgic_initialized(vcpu->kvm)))
>  		return;
>  
> +	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
> +		return;
> +

While I can see the READ_ONCE in list_empty(), it is not completely
obvious that the race with another CPU injecting an interrupt is safe
(if I get it correctly, it will have the same effect as if it was added
right after the critical section below).

Can we have a nice comment explaining this?

>  	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>  	vgic_flush_lr_state(vcpu);
>  	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> 

Thanks,

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

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

* [PATCH 2/9] KVM: arm/arm64: vgic: Avoid flushing vgic state when there's no pending IRQ
@ 2017-03-21 10:57     ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 10:57 UTC (permalink / raw)
  To: linux-arm-kernel

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Shih-Wei Li <shihwei@cs.columbia.edu>
> 
> We do not need to flush vgic states in each world switch unless
> there is pending IRQ queued to the vgic's ap list. We can thus reduce
> the overhead by not grabbing the spinlock and not making the extra
> function call to vgic_flush_lr_state.
> 
> Signed-off-by: Shih-Wei Li <shihwei@cs.columbia.edu>
> Signed-off-by: Christoffer Dall <cdall@linaro.org>
> ---
>  virt/kvm/arm/vgic/vgic.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 2ac0def..1436c2e 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -637,12 +637,17 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
>  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
>  void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>  {
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +
>  	if (unlikely(!vgic_initialized(vcpu->kvm)))
>  		return;
>  
>  	vgic_process_maintenance_interrupt(vcpu);
>  	vgic_fold_lr_state(vcpu);
>  	vgic_prune_ap_list(vcpu);
> +
> +	/* Make sure we can fast-path in flush_hwstate */
> +	vgic_cpu->used_lrs = 0;
>  }
>  
>  /* Flush our emulation state into the GIC hardware before entering the guest. */
> @@ -651,6 +656,9 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>  	if (unlikely(!vgic_initialized(vcpu->kvm)))
>  		return;
>  
> +	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
> +		return;
> +

While I can see the READ_ONCE in list_empty(), it is not completely
obvious that the race with another CPU injecting an interrupt is safe
(if I get it correctly, it will have the same effect as if it was added
right after the critical section below).

Can we have a nice comment explaining this?

>  	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>  	vgic_flush_lr_state(vcpu);
>  	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> 

Thanks,

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

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

* Re: [PATCH 3/9] KVM: arm/arm64: vgic: Get rid of live_lrs
  2017-03-20 10:58   ` Christoffer Dall
@ 2017-03-21 11:06     ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 11:06 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: kvm, Andre Przywara, Eric Auger, Christoffer Dall

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> There is no need to calculate and maintain live_lrs when we always
> populate the lowest numbered LRs first on every entry and clear all LRs
> on every exit.

Indeed, that's a leftover of the old vgic, where we were keeping things
in place and not always reallocating LRs like we do now.

> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

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

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

* [PATCH 3/9] KVM: arm/arm64: vgic: Get rid of live_lrs
@ 2017-03-21 11:06     ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 11:06 UTC (permalink / raw)
  To: linux-arm-kernel

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> There is no need to calculate and maintain live_lrs when we always
> populate the lowest numbered LRs first on every entry and clear all LRs
> on every exit.

Indeed, that's a leftover of the old vgic, where we were keeping things
in place and not always reallocating LRs like we do now.

> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

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

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

* Re: [PATCH 1/9] KVM: arm/arm64: vgic: Defer touching GICH_VMCR to vcpu_load/put
  2017-03-21 10:29     ` Marc Zyngier
@ 2017-03-21 11:16       ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 11:16 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, kvm, Andre Przywara, kvmarm, linux-arm-kernel

On Tue, Mar 21, 2017 at 10:29:08AM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > From: Christoffer Dall <cdall@cs.columbia.edu>
> > 
> > We don't have to save/restore the VMCR on every entry to/from the guest,
> > since on GICv2 we can access the control interface from EL1 and on VHE
> > systems with GICv3 we can access the control interface from KVM running
> > in EL2.
> > 
> > GICv3 systems without VHE becomes the rare case, which has to
> > save/restore the register on each round trip.
> > 
> > For in-context accesses to the VMCR, meaning emulation code needs access
> > to the value of the VCPU that is currently running within vcpu_load
> > and vcpu_put will detect that the it should load the VMCR from the
> > physical GIC instead of using the cached memory value.  While this extra
> > checking adds some code complexity we end up moving code out of the
> > critical path.
> > 
> > Note that userspace accesses may see out-of-date values if the VCPU is
> > running while accessing the VGIC state via the KVM device API, but this
> > is already the case.
> > 
> > Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> > Signed-off-by: Christoffer Dall <cdall@linaro.org>
> > ---
> >  arch/arm/include/asm/kvm_asm.h   |  3 +++
> >  arch/arm/kvm/arm.c               | 11 +++++-----
> >  arch/arm64/include/asm/kvm_asm.h |  2 ++
> >  include/kvm/arm_vgic.h           |  3 +++
> >  virt/kvm/arm/hyp/vgic-v2-sr.c    |  3 ---
> >  virt/kvm/arm/hyp/vgic-v3-sr.c    | 14 ++++++++----
> >  virt/kvm/arm/vgic/vgic-init.c    | 12 +++++++++++
> >  virt/kvm/arm/vgic/vgic-v2.c      | 46 ++++++++++++++++++++++++++++++++++++++--
> >  virt/kvm/arm/vgic/vgic-v3.c      | 42 ++++++++++++++++++++++++++++++++++--
> >  virt/kvm/arm/vgic/vgic.c         | 22 +++++++++++++++++++
> >  virt/kvm/arm/vgic/vgic.h         |  6 ++++++
> >  11 files changed, 148 insertions(+), 16 deletions(-)
> > 
> > diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
> > index 8ef0538..dd16044 100644
> > --- a/arch/arm/include/asm/kvm_asm.h
> > +++ b/arch/arm/include/asm/kvm_asm.h
> > @@ -75,7 +75,10 @@ extern void __init_stage2_translation(void);
> >  extern void __kvm_hyp_reset(unsigned long);
> >  
> >  extern u64 __vgic_v3_get_ich_vtr_el2(void);
> > +extern u64 __vgic_v3_read_vmcr(void);
> > +extern void __vgic_v3_write_vmcr(u32 vmcr);
> >  extern void __vgic_v3_init_lrs(void);
> > +
> >  #endif
> >  
> >  #endif /* __ARM_KVM_ASM_H__ */
> > diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> > index d775aac..cfdf2f5 100644
> > --- a/arch/arm/kvm/arm.c
> > +++ b/arch/arm/kvm/arm.c
> > @@ -348,15 +348,14 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> >  	vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
> >  
> >  	kvm_arm_set_running_vcpu(vcpu);
> > +
> > +	kvm_vgic_load(vcpu);
> >  }
> >  
> >  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
> >  {
> > -	/*
> > -	 * The arch-generic KVM code expects the cpu field of a vcpu to be -1
> > -	 * if the vcpu is no longer assigned to a cpu.  This is used for the
> > -	 * optimized make_all_cpus_request path.
> > -	 */
> > +	kvm_vgic_put(vcpu);
> > +
> >  	vcpu->cpu = -1;
> >  
> >  	kvm_arm_set_running_vcpu(NULL);
> > @@ -630,7 +629,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		 * non-preemptible context.
> >  		 */
> >  		preempt_disable();
> > +
> >  		kvm_pmu_flush_hwstate(vcpu);
> > +
> >  		kvm_timer_flush_hwstate(vcpu);
> >  		kvm_vgic_flush_hwstate(vcpu);
> >  
> > diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> > index ec3553eb..49f99cd 100644
> > --- a/arch/arm64/include/asm/kvm_asm.h
> > +++ b/arch/arm64/include/asm/kvm_asm.h
> > @@ -59,6 +59,8 @@ extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
> >  extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
> >  
> >  extern u64 __vgic_v3_get_ich_vtr_el2(void);
> > +extern u64 __vgic_v3_read_vmcr(void);
> > +extern void __vgic_v3_write_vmcr(u32 vmcr);
> >  extern void __vgic_v3_init_lrs(void);
> >  
> >  extern u32 __kvm_get_mdcr_el2(void);
> > diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> > index c0b3d99..8d7c3a7 100644
> > --- a/include/kvm/arm_vgic.h
> > +++ b/include/kvm/arm_vgic.h
> > @@ -307,6 +307,9 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
> >  
> >  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
> >  
> > +void kvm_vgic_load(struct kvm_vcpu *vcpu);
> > +void kvm_vgic_put(struct kvm_vcpu *vcpu);
> > +
> >  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> >  #define vgic_initialized(k)	((k)->arch.vgic.initialized)
> >  #define vgic_ready(k)		((k)->arch.vgic.ready)
> > diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
> > index c8aeb7b..d3d3b9b 100644
> > --- a/virt/kvm/arm/hyp/vgic-v2-sr.c
> > +++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
> > @@ -114,8 +114,6 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
> >  	if (!base)
> >  		return;
> >  
> > -	cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
> > -
> >  	if (vcpu->arch.vgic_cpu.live_lrs) {
> >  		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
> >  
> > @@ -165,7 +163,6 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
> >  		}
> >  	}
> >  
> > -	writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
> >  	vcpu->arch.vgic_cpu.live_lrs = live_lrs;
> >  }
> >  
> > diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> > index 3947095..e51ee7e 100644
> > --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> > +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> > @@ -159,8 +159,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
> >  	if (!cpu_if->vgic_sre)
> >  		dsb(st);
> >  
> > -	cpu_if->vgic_vmcr  = read_gicreg(ICH_VMCR_EL2);
> > -
> >  	if (vcpu->arch.vgic_cpu.live_lrs) {
> >  		int i;
> >  		u32 max_lr_idx, nr_pri_bits;
> > @@ -261,8 +259,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
> >  			live_lrs |= (1 << i);
> >  	}
> >  
> > -	write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
> > -
> >  	if (live_lrs) {
> >  		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
> >  
> > @@ -326,3 +322,13 @@ u64 __hyp_text __vgic_v3_get_ich_vtr_el2(void)
> >  {
> >  	return read_gicreg(ICH_VTR_EL2);
> >  }
> > +
> > +u64 __hyp_text __vgic_v3_read_vmcr(void)
> > +{
> > +	return read_gicreg(ICH_VMCR_EL2);
> > +}
> > +
> > +void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> > +{
> > +	write_gicreg(vmcr, ICH_VMCR_EL2);
> > +}
> > diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> > index 702f810..3762fd1 100644
> > --- a/virt/kvm/arm/vgic/vgic-init.c
> > +++ b/virt/kvm/arm/vgic/vgic-init.c
> > @@ -262,6 +262,18 @@ int vgic_init(struct kvm *kvm)
> >  	vgic_debug_init(kvm);
> >  
> >  	dist->initialized = true;
> > +
> > +	/*
> > +	 * If we're initializing GICv2 on-demand when first running the VCPU
> > +	 * then we need to load the VGIC state onto the CPU.  We can detect
> > +	 * this easily by checking if we are in between vcpu_load and vcpu_put
> > +	 * when we just initialized the VGIC.
> > +	 */
> > +	preempt_disable();
> > +	vcpu = kvm_arm_get_running_vcpu();
> > +	if (vcpu)
> > +		kvm_vgic_load(vcpu);
> > +	preempt_enable();
> >  out:
> >  	return ret;
> >  }
> > diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> > index 94cf4b9..dfe6e5e 100644
> > --- a/virt/kvm/arm/vgic/vgic-v2.c
> > +++ b/virt/kvm/arm/vgic/vgic-v2.c
> > @@ -199,6 +199,9 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
> >  
> >  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> >  {
> > +	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> > +	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
> > +	int cpu;
> >  	u32 vmcr;
> >  
> >  	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
> > @@ -209,12 +212,35 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> >  	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
> >  		GICH_VMCR_PRIMASK_MASK;
> >  
> > -	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
> > +	cpu_if->vgic_vmcr = vmcr;
> > +
> > +	cpu = get_cpu();
> > +	if (vcpu->cpu == cpu)
> > +		/*
> > +		 * We have run vcpu_load and we're on VHE which means the VMCR
> > +		 * has already been flushed to the CPU; flush it again.
> > +		 */
> 
> I don't understand this comment. What has VHE to do with this?
> 

Bah, I used to only do this on VHE systems and do the save/restore on
GICv3-non-vhe systems, but then I changed it to use kvm_call_hyp in
load/put, so the comment is out of date.  Thanks for spotting it.

> > +		writel_relaxed(vmcr, vgic->vctrl_base + GICH_VMCR);
> > +	put_cpu();
> 
> There is one thing I don't quite get: I thought we could only get there
> with a userspace access. I understand that we've run vcpu_load()
> already, 

Actually, I think I was completely misguided here; I don't think you can
ever end up here between vcpu_load and vcpu_put...

> and that we end-up with a stale configuration in the HW. But
> why do we need to immediately propagate it? Surely we can rely on the
> vcpu thread doing a vcpu_load itself to load the new value, right? I
> must be missing something...

... and you're right, there's no actual change in functionality in that
userspace should stop the VCPU to ensure an updated value when reading
back the VMCR-based register values.  So I can just get rid of this
nonsense.

> 
> >  }
> >  
> >  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> >  {
> > -	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
> > +	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> > +	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
> > +	int cpu;
> > +	u32 vmcr;
> > +
> > +	cpu = get_cpu();
> > +	if (vcpu->cpu == cpu)
> > +		/*
> > +		 * We have run vcpu_load and which means the VMCR
> > +		 * has already been flushed to the CPU; sync it back.
> > +		 */
> > +		cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
> > +	put_cpu();
> > +
> > +	vmcr = cpu_if->vgic_vmcr;
> 
> Same comment as above.
> 
Same answer.

I'll rework this.

Thanks,
-Christoffer

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

* [PATCH 1/9] KVM: arm/arm64: vgic: Defer touching GICH_VMCR to vcpu_load/put
@ 2017-03-21 11:16       ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 11:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 21, 2017 at 10:29:08AM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > From: Christoffer Dall <cdall@cs.columbia.edu>
> > 
> > We don't have to save/restore the VMCR on every entry to/from the guest,
> > since on GICv2 we can access the control interface from EL1 and on VHE
> > systems with GICv3 we can access the control interface from KVM running
> > in EL2.
> > 
> > GICv3 systems without VHE becomes the rare case, which has to
> > save/restore the register on each round trip.
> > 
> > For in-context accesses to the VMCR, meaning emulation code needs access
> > to the value of the VCPU that is currently running within vcpu_load
> > and vcpu_put will detect that the it should load the VMCR from the
> > physical GIC instead of using the cached memory value.  While this extra
> > checking adds some code complexity we end up moving code out of the
> > critical path.
> > 
> > Note that userspace accesses may see out-of-date values if the VCPU is
> > running while accessing the VGIC state via the KVM device API, but this
> > is already the case.
> > 
> > Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> > Signed-off-by: Christoffer Dall <cdall@linaro.org>
> > ---
> >  arch/arm/include/asm/kvm_asm.h   |  3 +++
> >  arch/arm/kvm/arm.c               | 11 +++++-----
> >  arch/arm64/include/asm/kvm_asm.h |  2 ++
> >  include/kvm/arm_vgic.h           |  3 +++
> >  virt/kvm/arm/hyp/vgic-v2-sr.c    |  3 ---
> >  virt/kvm/arm/hyp/vgic-v3-sr.c    | 14 ++++++++----
> >  virt/kvm/arm/vgic/vgic-init.c    | 12 +++++++++++
> >  virt/kvm/arm/vgic/vgic-v2.c      | 46 ++++++++++++++++++++++++++++++++++++++--
> >  virt/kvm/arm/vgic/vgic-v3.c      | 42 ++++++++++++++++++++++++++++++++++--
> >  virt/kvm/arm/vgic/vgic.c         | 22 +++++++++++++++++++
> >  virt/kvm/arm/vgic/vgic.h         |  6 ++++++
> >  11 files changed, 148 insertions(+), 16 deletions(-)
> > 
> > diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
> > index 8ef0538..dd16044 100644
> > --- a/arch/arm/include/asm/kvm_asm.h
> > +++ b/arch/arm/include/asm/kvm_asm.h
> > @@ -75,7 +75,10 @@ extern void __init_stage2_translation(void);
> >  extern void __kvm_hyp_reset(unsigned long);
> >  
> >  extern u64 __vgic_v3_get_ich_vtr_el2(void);
> > +extern u64 __vgic_v3_read_vmcr(void);
> > +extern void __vgic_v3_write_vmcr(u32 vmcr);
> >  extern void __vgic_v3_init_lrs(void);
> > +
> >  #endif
> >  
> >  #endif /* __ARM_KVM_ASM_H__ */
> > diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> > index d775aac..cfdf2f5 100644
> > --- a/arch/arm/kvm/arm.c
> > +++ b/arch/arm/kvm/arm.c
> > @@ -348,15 +348,14 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> >  	vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
> >  
> >  	kvm_arm_set_running_vcpu(vcpu);
> > +
> > +	kvm_vgic_load(vcpu);
> >  }
> >  
> >  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
> >  {
> > -	/*
> > -	 * The arch-generic KVM code expects the cpu field of a vcpu to be -1
> > -	 * if the vcpu is no longer assigned to a cpu.  This is used for the
> > -	 * optimized make_all_cpus_request path.
> > -	 */
> > +	kvm_vgic_put(vcpu);
> > +
> >  	vcpu->cpu = -1;
> >  
> >  	kvm_arm_set_running_vcpu(NULL);
> > @@ -630,7 +629,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		 * non-preemptible context.
> >  		 */
> >  		preempt_disable();
> > +
> >  		kvm_pmu_flush_hwstate(vcpu);
> > +
> >  		kvm_timer_flush_hwstate(vcpu);
> >  		kvm_vgic_flush_hwstate(vcpu);
> >  
> > diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> > index ec3553eb..49f99cd 100644
> > --- a/arch/arm64/include/asm/kvm_asm.h
> > +++ b/arch/arm64/include/asm/kvm_asm.h
> > @@ -59,6 +59,8 @@ extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
> >  extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
> >  
> >  extern u64 __vgic_v3_get_ich_vtr_el2(void);
> > +extern u64 __vgic_v3_read_vmcr(void);
> > +extern void __vgic_v3_write_vmcr(u32 vmcr);
> >  extern void __vgic_v3_init_lrs(void);
> >  
> >  extern u32 __kvm_get_mdcr_el2(void);
> > diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> > index c0b3d99..8d7c3a7 100644
> > --- a/include/kvm/arm_vgic.h
> > +++ b/include/kvm/arm_vgic.h
> > @@ -307,6 +307,9 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
> >  
> >  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
> >  
> > +void kvm_vgic_load(struct kvm_vcpu *vcpu);
> > +void kvm_vgic_put(struct kvm_vcpu *vcpu);
> > +
> >  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> >  #define vgic_initialized(k)	((k)->arch.vgic.initialized)
> >  #define vgic_ready(k)		((k)->arch.vgic.ready)
> > diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
> > index c8aeb7b..d3d3b9b 100644
> > --- a/virt/kvm/arm/hyp/vgic-v2-sr.c
> > +++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
> > @@ -114,8 +114,6 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
> >  	if (!base)
> >  		return;
> >  
> > -	cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
> > -
> >  	if (vcpu->arch.vgic_cpu.live_lrs) {
> >  		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
> >  
> > @@ -165,7 +163,6 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
> >  		}
> >  	}
> >  
> > -	writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
> >  	vcpu->arch.vgic_cpu.live_lrs = live_lrs;
> >  }
> >  
> > diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> > index 3947095..e51ee7e 100644
> > --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> > +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> > @@ -159,8 +159,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
> >  	if (!cpu_if->vgic_sre)
> >  		dsb(st);
> >  
> > -	cpu_if->vgic_vmcr  = read_gicreg(ICH_VMCR_EL2);
> > -
> >  	if (vcpu->arch.vgic_cpu.live_lrs) {
> >  		int i;
> >  		u32 max_lr_idx, nr_pri_bits;
> > @@ -261,8 +259,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
> >  			live_lrs |= (1 << i);
> >  	}
> >  
> > -	write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
> > -
> >  	if (live_lrs) {
> >  		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
> >  
> > @@ -326,3 +322,13 @@ u64 __hyp_text __vgic_v3_get_ich_vtr_el2(void)
> >  {
> >  	return read_gicreg(ICH_VTR_EL2);
> >  }
> > +
> > +u64 __hyp_text __vgic_v3_read_vmcr(void)
> > +{
> > +	return read_gicreg(ICH_VMCR_EL2);
> > +}
> > +
> > +void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> > +{
> > +	write_gicreg(vmcr, ICH_VMCR_EL2);
> > +}
> > diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> > index 702f810..3762fd1 100644
> > --- a/virt/kvm/arm/vgic/vgic-init.c
> > +++ b/virt/kvm/arm/vgic/vgic-init.c
> > @@ -262,6 +262,18 @@ int vgic_init(struct kvm *kvm)
> >  	vgic_debug_init(kvm);
> >  
> >  	dist->initialized = true;
> > +
> > +	/*
> > +	 * If we're initializing GICv2 on-demand when first running the VCPU
> > +	 * then we need to load the VGIC state onto the CPU.  We can detect
> > +	 * this easily by checking if we are in between vcpu_load and vcpu_put
> > +	 * when we just initialized the VGIC.
> > +	 */
> > +	preempt_disable();
> > +	vcpu = kvm_arm_get_running_vcpu();
> > +	if (vcpu)
> > +		kvm_vgic_load(vcpu);
> > +	preempt_enable();
> >  out:
> >  	return ret;
> >  }
> > diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> > index 94cf4b9..dfe6e5e 100644
> > --- a/virt/kvm/arm/vgic/vgic-v2.c
> > +++ b/virt/kvm/arm/vgic/vgic-v2.c
> > @@ -199,6 +199,9 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
> >  
> >  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> >  {
> > +	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> > +	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
> > +	int cpu;
> >  	u32 vmcr;
> >  
> >  	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
> > @@ -209,12 +212,35 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> >  	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
> >  		GICH_VMCR_PRIMASK_MASK;
> >  
> > -	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
> > +	cpu_if->vgic_vmcr = vmcr;
> > +
> > +	cpu = get_cpu();
> > +	if (vcpu->cpu == cpu)
> > +		/*
> > +		 * We have run vcpu_load and we're on VHE which means the VMCR
> > +		 * has already been flushed to the CPU; flush it again.
> > +		 */
> 
> I don't understand this comment. What has VHE to do with this?
> 

Bah, I used to only do this on VHE systems and do the save/restore on
GICv3-non-vhe systems, but then I changed it to use kvm_call_hyp in
load/put, so the comment is out of date.  Thanks for spotting it.

> > +		writel_relaxed(vmcr, vgic->vctrl_base + GICH_VMCR);
> > +	put_cpu();
> 
> There is one thing I don't quite get: I thought we could only get there
> with a userspace access. I understand that we've run vcpu_load()
> already, 

Actually, I think I was completely misguided here; I don't think you can
ever end up here between vcpu_load and vcpu_put...

> and that we end-up with a stale configuration in the HW. But
> why do we need to immediately propagate it? Surely we can rely on the
> vcpu thread doing a vcpu_load itself to load the new value, right? I
> must be missing something...

... and you're right, there's no actual change in functionality in that
userspace should stop the VCPU to ensure an updated value when reading
back the VMCR-based register values.  So I can just get rid of this
nonsense.

> 
> >  }
> >  
> >  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> >  {
> > -	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
> > +	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> > +	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
> > +	int cpu;
> > +	u32 vmcr;
> > +
> > +	cpu = get_cpu();
> > +	if (vcpu->cpu == cpu)
> > +		/*
> > +		 * We have run vcpu_load and which means the VMCR
> > +		 * has already been flushed to the CPU; sync it back.
> > +		 */
> > +		cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
> > +	put_cpu();
> > +
> > +	vmcr = cpu_if->vgic_vmcr;
> 
> Same comment as above.
> 
Same answer.

I'll rework this.

Thanks,
-Christoffer

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

* Re: [PATCH 2/9] KVM: arm/arm64: vgic: Avoid flushing vgic state when there's no pending IRQ
  2017-03-21 10:57     ` Marc Zyngier
@ 2017-03-21 11:17       ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 11:17 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, Andre Przywara, linux-arm-kernel, kvmarm, Shih-Wei Li

On Tue, Mar 21, 2017 at 10:57:49AM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > From: Shih-Wei Li <shihwei@cs.columbia.edu>
> > 
> > We do not need to flush vgic states in each world switch unless
> > there is pending IRQ queued to the vgic's ap list. We can thus reduce
> > the overhead by not grabbing the spinlock and not making the extra
> > function call to vgic_flush_lr_state.
> > 
> > Signed-off-by: Shih-Wei Li <shihwei@cs.columbia.edu>
> > Signed-off-by: Christoffer Dall <cdall@linaro.org>
> > ---
> >  virt/kvm/arm/vgic/vgic.c | 8 ++++++++
> >  1 file changed, 8 insertions(+)
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > index 2ac0def..1436c2e 100644
> > --- a/virt/kvm/arm/vgic/vgic.c
> > +++ b/virt/kvm/arm/vgic/vgic.c
> > @@ -637,12 +637,17 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> >  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> >  void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> >  {
> > +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> > +
> >  	if (unlikely(!vgic_initialized(vcpu->kvm)))
> >  		return;
> >  
> >  	vgic_process_maintenance_interrupt(vcpu);
> >  	vgic_fold_lr_state(vcpu);
> >  	vgic_prune_ap_list(vcpu);
> > +
> > +	/* Make sure we can fast-path in flush_hwstate */
> > +	vgic_cpu->used_lrs = 0;
> >  }
> >  
> >  /* Flush our emulation state into the GIC hardware before entering the guest. */
> > @@ -651,6 +656,9 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> >  	if (unlikely(!vgic_initialized(vcpu->kvm)))
> >  		return;
> >  
> > +	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
> > +		return;
> > +
> 
> While I can see the READ_ONCE in list_empty(), it is not completely
> obvious that the race with another CPU injecting an interrupt is safe
> (if I get it correctly, it will have the same effect as if it was added
> right after the critical section below).

Yes, you either observe virtual interrupts or not, that's a benign race.

> 
> Can we have a nice comment explaining this?
> 

You sure can, I will add something.

> >  	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >  	vgic_flush_lr_state(vcpu);
> >  	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> > 
> 

Thanks,
-Christoffer

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

* [PATCH 2/9] KVM: arm/arm64: vgic: Avoid flushing vgic state when there's no pending IRQ
@ 2017-03-21 11:17       ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 11:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 21, 2017 at 10:57:49AM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > From: Shih-Wei Li <shihwei@cs.columbia.edu>
> > 
> > We do not need to flush vgic states in each world switch unless
> > there is pending IRQ queued to the vgic's ap list. We can thus reduce
> > the overhead by not grabbing the spinlock and not making the extra
> > function call to vgic_flush_lr_state.
> > 
> > Signed-off-by: Shih-Wei Li <shihwei@cs.columbia.edu>
> > Signed-off-by: Christoffer Dall <cdall@linaro.org>
> > ---
> >  virt/kvm/arm/vgic/vgic.c | 8 ++++++++
> >  1 file changed, 8 insertions(+)
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > index 2ac0def..1436c2e 100644
> > --- a/virt/kvm/arm/vgic/vgic.c
> > +++ b/virt/kvm/arm/vgic/vgic.c
> > @@ -637,12 +637,17 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> >  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> >  void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> >  {
> > +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> > +
> >  	if (unlikely(!vgic_initialized(vcpu->kvm)))
> >  		return;
> >  
> >  	vgic_process_maintenance_interrupt(vcpu);
> >  	vgic_fold_lr_state(vcpu);
> >  	vgic_prune_ap_list(vcpu);
> > +
> > +	/* Make sure we can fast-path in flush_hwstate */
> > +	vgic_cpu->used_lrs = 0;
> >  }
> >  
> >  /* Flush our emulation state into the GIC hardware before entering the guest. */
> > @@ -651,6 +656,9 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> >  	if (unlikely(!vgic_initialized(vcpu->kvm)))
> >  		return;
> >  
> > +	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
> > +		return;
> > +
> 
> While I can see the READ_ONCE in list_empty(), it is not completely
> obvious that the race with another CPU injecting an interrupt is safe
> (if I get it correctly, it will have the same effect as if it was added
> right after the critical section below).

Yes, you either observe virtual interrupts or not, that's a benign race.

> 
> Can we have a nice comment explaining this?
> 

You sure can, I will add something.

> >  	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >  	vgic_flush_lr_state(vcpu);
> >  	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> > 
> 

Thanks,
-Christoffer

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

* Re: [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operation
  2017-03-20 10:58   ` Christoffer Dall
@ 2017-03-21 11:36     ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 11:36 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel; +Cc: Andre Przywara, kvm

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Since we always read back the LRs that we wrote to the guest and the
> MISR and EISR registers simply provide a summary of the configuration of
> the bits in the LRs, there is really no need to read back those status
> registers and process them.  We can might as well just signal the
> notifyfd when folding the LR state and save some cycles in the process.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  virt/kvm/arm/vgic/vgic-v2.c | 55 ++++++++++-----------------------------------
>  virt/kvm/arm/vgic/vgic-v3.c | 47 +++++++++++---------------------------
>  virt/kvm/arm/vgic/vgic.c    |  8 +++----
>  virt/kvm/arm/vgic/vgic.h    |  4 ++--
>  4 files changed, 31 insertions(+), 83 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index dfe6e5e..0172754 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -22,20 +22,6 @@
>  
>  #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;
> -}
> -

Getting rid of u64_to_bitmask makes me feel slightly better...

>  static inline void vgic_v2_write_lr(int lr, u32 val)
>  {
>  	void __iomem *base = kvm_vgic_global_state.vctrl_base;
> @@ -51,38 +37,10 @@ void vgic_v2_init_lrs(void)
>  		vgic_v2_write_lr(i, 0);
>  }
>  
> -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> +void vgic_v2_clear_uie(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);
> -
> -			/* Only SPIs require notification */
> -			if (vgic_valid_spi(vcpu->kvm, intid))
> -				kvm_notify_acked_irq(vcpu->kvm, 0,
> -						     intid - VGIC_NR_PRIVATE_IRQS);
> -		}
> -	}
> -
> -	/* 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)
> @@ -92,6 +50,12 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>  	cpuif->vgic_hcr |= GICH_HCR_UIE;
>  }
>  
> +static bool lr_signals_eoi_mi(u32 lr_val)
> +{
> +	return !(lr_val & GICH_LR_STATE) && (lr_val & GICH_LR_EOI) &&
> +	       !(lr_val & GICH_LR_HW);
> +}
> +
>  /*
>   * transfer the content of the LRs back into the corresponding ap_list:
>   * - active bit is transferred as is
> @@ -109,6 +73,11 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>  		u32 intid = val & GICH_LR_VIRTUALID;
>  		struct vgic_irq *irq;
>  
> +		/* Notify fds when the guest EOI'ed a level-triggered SPI */
> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>  
>  		spin_lock(&irq->irq_lock);
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 3d7796c..7880c5c 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -21,42 +21,9 @@
>  
>  #include "vgic.h"
>  
> -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +void vgic_v3_clear_uie(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);
> -
> -			/* Only SPIs require notification */
> -			if (vgic_valid_spi(vcpu->kvm, intid))
> -				kvm_notify_acked_irq(vcpu->kvm, 0,
> -						     intid - VGIC_NR_PRIVATE_IRQS);
> -		}
> -
> -		/*
> -		 * 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;
>  }
>  
> @@ -67,6 +34,12 @@ void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>  	cpuif->vgic_hcr |= ICH_HCR_UIE;
>  }
>  
> +static bool lr_signals_eoi_mi(u64 lr_val)
> +{
> +	return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) &&
> +	       !(lr_val & ICH_LR_HW);
> +}
> +
>  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>  {
>  	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> @@ -82,6 +55,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>  			intid = val & ICH_LR_VIRTUAL_ID_MASK;
>  		else
>  			intid = val & GICH_LR_VIRTUALID;
> +
> +		/* Notify fds when the guest EOI'ed a level-triggered IRQ */
> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>  		if (!irq)	/* An LPI could have been unmapped. */
>  			continue;
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 1436c2e..f5b3c25 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -527,12 +527,12 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
>  	spin_unlock(&vgic_cpu->ap_list_lock);
>  }
>  
> -static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +static inline void vgic_clear_uie(struct kvm_vcpu *vcpu)
>  {
>  	if (kvm_vgic_global_state.type == VGIC_V2)
> -		vgic_v2_process_maintenance(vcpu);
> +		vgic_v2_clear_uie(vcpu);
>  	else
> -		vgic_v3_process_maintenance(vcpu);
> +		vgic_v3_clear_uie(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> @@ -642,7 +642,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>  	if (unlikely(!vgic_initialized(vcpu->kvm)))
>  		return;
>  
> -	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_clear_uie(vcpu);
>  	vgic_fold_lr_state(vcpu);

nit: If you moved vgic_*_clear_uie() into vgic_*_fold_lr_state, you
could get rid of this call, extra prototypes, and save yourself the
extra check. Not a big deal though.

>  	vgic_prune_ap_list(vcpu);
>  
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 3f64220..72ba9ee 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -112,7 +112,7 @@ void vgic_kick_vcpus(struct kvm *kvm);
>  int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
>  		      phys_addr_t addr, phys_addr_t alignment);
>  
> -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v2_clear_uie(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);
> @@ -143,7 +143,7 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
>  	kref_get(&irq->refcount);
>  }
>  
> -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v3_clear_uie(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);
> 

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

Thanks,

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

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

* [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operation
@ 2017-03-21 11:36     ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Since we always read back the LRs that we wrote to the guest and the
> MISR and EISR registers simply provide a summary of the configuration of
> the bits in the LRs, there is really no need to read back those status
> registers and process them.  We can might as well just signal the
> notifyfd when folding the LR state and save some cycles in the process.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  virt/kvm/arm/vgic/vgic-v2.c | 55 ++++++++++-----------------------------------
>  virt/kvm/arm/vgic/vgic-v3.c | 47 +++++++++++---------------------------
>  virt/kvm/arm/vgic/vgic.c    |  8 +++----
>  virt/kvm/arm/vgic/vgic.h    |  4 ++--
>  4 files changed, 31 insertions(+), 83 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index dfe6e5e..0172754 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -22,20 +22,6 @@
>  
>  #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;
> -}
> -

Getting rid of u64_to_bitmask makes me feel slightly better...

>  static inline void vgic_v2_write_lr(int lr, u32 val)
>  {
>  	void __iomem *base = kvm_vgic_global_state.vctrl_base;
> @@ -51,38 +37,10 @@ void vgic_v2_init_lrs(void)
>  		vgic_v2_write_lr(i, 0);
>  }
>  
> -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> +void vgic_v2_clear_uie(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);
> -
> -			/* Only SPIs require notification */
> -			if (vgic_valid_spi(vcpu->kvm, intid))
> -				kvm_notify_acked_irq(vcpu->kvm, 0,
> -						     intid - VGIC_NR_PRIVATE_IRQS);
> -		}
> -	}
> -
> -	/* 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)
> @@ -92,6 +50,12 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>  	cpuif->vgic_hcr |= GICH_HCR_UIE;
>  }
>  
> +static bool lr_signals_eoi_mi(u32 lr_val)
> +{
> +	return !(lr_val & GICH_LR_STATE) && (lr_val & GICH_LR_EOI) &&
> +	       !(lr_val & GICH_LR_HW);
> +}
> +
>  /*
>   * transfer the content of the LRs back into the corresponding ap_list:
>   * - active bit is transferred as is
> @@ -109,6 +73,11 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>  		u32 intid = val & GICH_LR_VIRTUALID;
>  		struct vgic_irq *irq;
>  
> +		/* Notify fds when the guest EOI'ed a level-triggered SPI */
> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>  
>  		spin_lock(&irq->irq_lock);
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 3d7796c..7880c5c 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -21,42 +21,9 @@
>  
>  #include "vgic.h"
>  
> -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +void vgic_v3_clear_uie(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);
> -
> -			/* Only SPIs require notification */
> -			if (vgic_valid_spi(vcpu->kvm, intid))
> -				kvm_notify_acked_irq(vcpu->kvm, 0,
> -						     intid - VGIC_NR_PRIVATE_IRQS);
> -		}
> -
> -		/*
> -		 * 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;
>  }
>  
> @@ -67,6 +34,12 @@ void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>  	cpuif->vgic_hcr |= ICH_HCR_UIE;
>  }
>  
> +static bool lr_signals_eoi_mi(u64 lr_val)
> +{
> +	return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) &&
> +	       !(lr_val & ICH_LR_HW);
> +}
> +
>  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>  {
>  	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> @@ -82,6 +55,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>  			intid = val & ICH_LR_VIRTUAL_ID_MASK;
>  		else
>  			intid = val & GICH_LR_VIRTUALID;
> +
> +		/* Notify fds when the guest EOI'ed a level-triggered IRQ */
> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>  		if (!irq)	/* An LPI could have been unmapped. */
>  			continue;
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 1436c2e..f5b3c25 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -527,12 +527,12 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
>  	spin_unlock(&vgic_cpu->ap_list_lock);
>  }
>  
> -static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +static inline void vgic_clear_uie(struct kvm_vcpu *vcpu)
>  {
>  	if (kvm_vgic_global_state.type == VGIC_V2)
> -		vgic_v2_process_maintenance(vcpu);
> +		vgic_v2_clear_uie(vcpu);
>  	else
> -		vgic_v3_process_maintenance(vcpu);
> +		vgic_v3_clear_uie(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> @@ -642,7 +642,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>  	if (unlikely(!vgic_initialized(vcpu->kvm)))
>  		return;
>  
> -	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_clear_uie(vcpu);
>  	vgic_fold_lr_state(vcpu);

nit: If you moved vgic_*_clear_uie() into vgic_*_fold_lr_state, you
could get rid of this call, extra prototypes, and save yourself the
extra check. Not a big deal though.

>  	vgic_prune_ap_list(vcpu);
>  
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 3f64220..72ba9ee 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -112,7 +112,7 @@ void vgic_kick_vcpus(struct kvm *kvm);
>  int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
>  		      phys_addr_t addr, phys_addr_t alignment);
>  
> -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v2_clear_uie(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);
> @@ -143,7 +143,7 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
>  	kref_get(&irq->refcount);
>  }
>  
> -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v3_clear_uie(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);
> 

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

Thanks,

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

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

* Re: [PATCH 5/9] KVM: arm/arm64: vgic: Get rid of unnecessary save_maint_int_state
  2017-03-20 10:58   ` Christoffer Dall
@ 2017-03-21 11:44     ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 11:44 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel; +Cc: Andre Przywara, kvm

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Now when we don't look at the MISR and EISR values anymore, we can get
> rid of the logic to save them in the GIC save/restore code.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

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

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

* [PATCH 5/9] KVM: arm/arm64: vgic: Get rid of unnecessary save_maint_int_state
@ 2017-03-21 11:44     ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Now when we don't look at the MISR and EISR values anymore, we can get
> rid of the logic to save them in the GIC save/restore code.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

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

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

* Re: [PATCH 6/9] KVM: arm/arm64: vgic: Get rid of MISR and EISR fields
  2017-03-20 10:58   ` Christoffer Dall
@ 2017-03-21 11:45     ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 11:45 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel; +Cc: Andre Przywara, kvm

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> We don't use these fields anymore so let's nuke them completely.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

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

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

* [PATCH 6/9] KVM: arm/arm64: vgic: Get rid of MISR and EISR fields
@ 2017-03-21 11:45     ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 11:45 UTC (permalink / raw)
  To: linux-arm-kernel

On 20/03/17 10:58, Christoffer Dall wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> We don't use these fields anymore so let's nuke them completely.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

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

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

* Re: [PATCH 7/9] KVM: arm/arm64: vgic: Implement early VGIC init functionality
  2017-03-20 10:58   ` Christoffer Dall
@ 2017-03-21 12:05     ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 12:05 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: kvm, Andre Przywara, Eric Auger

On 20/03/17 10:58, Christoffer Dall wrote:
> Implement early initialization for both the distributor and the CPU
> interfaces.  The basic idea is that even though the VGIC is not
> functional or not requested from user space, the critical path of the
> run loop can still call VGIC functions that just won't do anything,
> without them having to check additional initialization flags to ensure
> they don't look at uninitialized data structures.
> 
> Signed-off-by: Christoffer Dall <cdall@linaro.org>
> ---
>  virt/kvm/arm/vgic/vgic-init.c | 96 +++++++++++++++++++++++++------------------
>  1 file changed, 56 insertions(+), 40 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index 3762fd1..25fd1b9 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -24,7 +24,12 @@
>  
>  /*
>   * Initialization rules: there are multiple stages to the vgic
> - * initialization, both for the distributor and the CPU interfaces.
> + * initialization, both for the distributor and the CPU interfaces.  The basic
> + * idea is that even though the VGIC is not functional or not requested from
> + * user space, the critical path of the run loop can still call VGIC functions
> + * that just won't do anything, without them having to check additional
> + * initialization flags to ensure they don't look at uninitialized data
> + * structures.
>   *
>   * Distributor:
>   *
> @@ -39,23 +44,67 @@
>   *
>   * CPU Interface:
>   *
> - * - kvm_vgic_cpu_early_init(): initialization of static data that
> + * - kvm_vgic_vcpu_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
> +/**
> + * kvm_vgic_early_init() - Initialize static VGIC VCPU data structures
> + * @kvm: The VM whose VGIC districutor should be initialized
> + *
> + * Only do initialization of static structures that don't require any
> + * allocation or sizing information from userspace.  vgic_init() called
> + * kvm_vgic_dist_init() which takes care of the rest.
>   */
>  void kvm_vgic_early_init(struct kvm *kvm)
>  {
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +
> +	INIT_LIST_HEAD(&dist->lpi_list_head);
> +	spin_lock_init(&dist->lpi_list_lock);
>  }
>  
> +/**
> + * kvm_vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
> + * @vcpu: The VCPU whose VGIC data structures whould be initialized
> + *
> + * Only do initialization, but do not actually enable the VGIC CPU interface
> + * yet.
> + */
>  void kvm_vgic_vcpu_early_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;
> +		kref_init(&irq->refcount);
> +		if (vgic_irq_is_sgi(i)) {
> +			/* SGIs */
> +			irq->enabled = 1;
> +			irq->config = VGIC_CONFIG_EDGE;
> +		} else {
> +			/* PPIs */
> +			irq->config = VGIC_CONFIG_LEVEL;
> +		}
> +	}
>  }
>  
>  /* CREATION */
> @@ -148,9 +197,6 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
>  	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
>  	int i;
>  
> -	INIT_LIST_HEAD(&dist->lpi_list_head);
> -	spin_lock_init(&dist->lpi_list_lock);
> -
>  	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
>  	if (!dist->spis)
>  		return  -ENOMEM;
> @@ -181,41 +227,11 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
>  }
>  
>  /**
> - * kvm_vgic_vcpu_init: initialize the vcpu data structures and
> - * enable the VCPU interface
> - * @vcpu: the VCPU which's VGIC should be initialized
> + * kvm_vgic_vcpu_init() - Enable the VCPU interface
> + * @vcpu: the VCPU which's VGIC should be enabled
>   */
>  static 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;
> -		kref_init(&irq->refcount);
> -		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
> 

Since this function is now about enabling the vgic on a given vcpu,
shouldn't the name reflect this? Other than that:

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

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

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

* [PATCH 7/9] KVM: arm/arm64: vgic: Implement early VGIC init functionality
@ 2017-03-21 12:05     ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 12:05 UTC (permalink / raw)
  To: linux-arm-kernel

On 20/03/17 10:58, Christoffer Dall wrote:
> Implement early initialization for both the distributor and the CPU
> interfaces.  The basic idea is that even though the VGIC is not
> functional or not requested from user space, the critical path of the
> run loop can still call VGIC functions that just won't do anything,
> without them having to check additional initialization flags to ensure
> they don't look at uninitialized data structures.
> 
> Signed-off-by: Christoffer Dall <cdall@linaro.org>
> ---
>  virt/kvm/arm/vgic/vgic-init.c | 96 +++++++++++++++++++++++++------------------
>  1 file changed, 56 insertions(+), 40 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index 3762fd1..25fd1b9 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -24,7 +24,12 @@
>  
>  /*
>   * Initialization rules: there are multiple stages to the vgic
> - * initialization, both for the distributor and the CPU interfaces.
> + * initialization, both for the distributor and the CPU interfaces.  The basic
> + * idea is that even though the VGIC is not functional or not requested from
> + * user space, the critical path of the run loop can still call VGIC functions
> + * that just won't do anything, without them having to check additional
> + * initialization flags to ensure they don't look at uninitialized data
> + * structures.
>   *
>   * Distributor:
>   *
> @@ -39,23 +44,67 @@
>   *
>   * CPU Interface:
>   *
> - * - kvm_vgic_cpu_early_init(): initialization of static data that
> + * - kvm_vgic_vcpu_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
> +/**
> + * kvm_vgic_early_init() - Initialize static VGIC VCPU data structures
> + * @kvm: The VM whose VGIC districutor should be initialized
> + *
> + * Only do initialization of static structures that don't require any
> + * allocation or sizing information from userspace.  vgic_init() called
> + * kvm_vgic_dist_init() which takes care of the rest.
>   */
>  void kvm_vgic_early_init(struct kvm *kvm)
>  {
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +
> +	INIT_LIST_HEAD(&dist->lpi_list_head);
> +	spin_lock_init(&dist->lpi_list_lock);
>  }
>  
> +/**
> + * kvm_vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
> + * @vcpu: The VCPU whose VGIC data structures whould be initialized
> + *
> + * Only do initialization, but do not actually enable the VGIC CPU interface
> + * yet.
> + */
>  void kvm_vgic_vcpu_early_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;
> +		kref_init(&irq->refcount);
> +		if (vgic_irq_is_sgi(i)) {
> +			/* SGIs */
> +			irq->enabled = 1;
> +			irq->config = VGIC_CONFIG_EDGE;
> +		} else {
> +			/* PPIs */
> +			irq->config = VGIC_CONFIG_LEVEL;
> +		}
> +	}
>  }
>  
>  /* CREATION */
> @@ -148,9 +197,6 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
>  	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
>  	int i;
>  
> -	INIT_LIST_HEAD(&dist->lpi_list_head);
> -	spin_lock_init(&dist->lpi_list_lock);
> -
>  	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
>  	if (!dist->spis)
>  		return  -ENOMEM;
> @@ -181,41 +227,11 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
>  }
>  
>  /**
> - * kvm_vgic_vcpu_init: initialize the vcpu data structures and
> - * enable the VCPU interface
> - * @vcpu: the VCPU which's VGIC should be initialized
> + * kvm_vgic_vcpu_init() - Enable the VCPU interface
> + * @vcpu: the VCPU which's VGIC should be enabled
>   */
>  static 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;
> -		kref_init(&irq->refcount);
> -		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
> 

Since this function is now about enabling the vgic on a given vcpu,
shouldn't the name reflect this? Other than that:

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

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

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

* Re: [PATCH 8/9] KVM: arm/arm64: vgic: Don't check vgic_initialized in flush_hwstate
  2017-03-20 10:58   ` Christoffer Dall
@ 2017-03-21 12:08     ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 12:08 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel; +Cc: Andre Przywara, kvm

On 20/03/17 10:58, Christoffer Dall wrote:
> Now when we do an early init of the static parts of the VGIC data
> structures, we can do things like checking if the AP lists are empty
> directly without having to explicitly check if the vgic is initialized
> and reduce a bit of work in our criticial path.

                                  critical

> Note: list_empty is a single atomic read (uses READ_ONCE) and can
> therefore check if a list is empty or not without the need to take the
> spinlock protecting the list.

This note might be better placed in patch #2.

> 
> Signed-off-by: Christoffer Dall <cdall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

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

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

* [PATCH 8/9] KVM: arm/arm64: vgic: Don't check vgic_initialized in flush_hwstate
@ 2017-03-21 12:08     ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 12:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 20/03/17 10:58, Christoffer Dall wrote:
> Now when we do an early init of the static parts of the VGIC data
> structures, we can do things like checking if the AP lists are empty
> directly without having to explicitly check if the vgic is initialized
> and reduce a bit of work in our criticial path.

                                  critical

> Note: list_empty is a single atomic read (uses READ_ONCE) and can
> therefore check if a list is empty or not without the need to take the
> spinlock protecting the list.

This note might be better placed in patch #2.

> 
> Signed-off-by: Christoffer Dall <cdall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

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

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

* Re: [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operationjjjj
  2017-03-21 11:36     ` Marc Zyngier
@ 2017-03-21 12:26       ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 12:26 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, Andre Przywara, linux-arm-kernel, kvmarm

On Tue, Mar 21, 2017 at 11:36:19AM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > From: Christoffer Dall <christoffer.dall@linaro.org>
> > 
> > Since we always read back the LRs that we wrote to the guest and the
> > MISR and EISR registers simply provide a summary of the configuration of
> > the bits in the LRs, there is really no need to read back those status
> > registers and process them.  We can might as well just signal the
> > notifyfd when folding the LR state and save some cycles in the process.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  virt/kvm/arm/vgic/vgic-v2.c | 55 ++++++++++-----------------------------------
> >  virt/kvm/arm/vgic/vgic-v3.c | 47 +++++++++++---------------------------
> >  virt/kvm/arm/vgic/vgic.c    |  8 +++----
> >  virt/kvm/arm/vgic/vgic.h    |  4 ++--
> >  4 files changed, 31 insertions(+), 83 deletions(-)
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> > index dfe6e5e..0172754 100644
> > --- a/virt/kvm/arm/vgic/vgic-v2.c
> > +++ b/virt/kvm/arm/vgic/vgic-v2.c
> > @@ -22,20 +22,6 @@
> >  
> >  #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;
> > -}
> > -
> 
> Getting rid of u64_to_bitmask makes me feel slightly better...
> 
> >  static inline void vgic_v2_write_lr(int lr, u32 val)
> >  {
> >  	void __iomem *base = kvm_vgic_global_state.vctrl_base;
> > @@ -51,38 +37,10 @@ void vgic_v2_init_lrs(void)
> >  		vgic_v2_write_lr(i, 0);
> >  }
> >  
> > -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> > +void vgic_v2_clear_uie(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);
> > -
> > -			/* Only SPIs require notification */
> > -			if (vgic_valid_spi(vcpu->kvm, intid))
> > -				kvm_notify_acked_irq(vcpu->kvm, 0,
> > -						     intid - VGIC_NR_PRIVATE_IRQS);
> > -		}
> > -	}
> > -
> > -	/* 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)
> > @@ -92,6 +50,12 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> >  	cpuif->vgic_hcr |= GICH_HCR_UIE;
> >  }
> >  
> > +static bool lr_signals_eoi_mi(u32 lr_val)
> > +{
> > +	return !(lr_val & GICH_LR_STATE) && (lr_val & GICH_LR_EOI) &&
> > +	       !(lr_val & GICH_LR_HW);
> > +}
> > +
> >  /*
> >   * transfer the content of the LRs back into the corresponding ap_list:
> >   * - active bit is transferred as is
> > @@ -109,6 +73,11 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> >  		u32 intid = val & GICH_LR_VIRTUALID;
> >  		struct vgic_irq *irq;
> >  
> > +		/* Notify fds when the guest EOI'ed a level-triggered SPI */
> > +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> > +			kvm_notify_acked_irq(vcpu->kvm, 0,
> > +					     intid - VGIC_NR_PRIVATE_IRQS);
> > +
> >  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >  
> >  		spin_lock(&irq->irq_lock);
> > diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> > index 3d7796c..7880c5c 100644
> > --- a/virt/kvm/arm/vgic/vgic-v3.c
> > +++ b/virt/kvm/arm/vgic/vgic-v3.c
> > @@ -21,42 +21,9 @@
> >  
> >  #include "vgic.h"
> >  
> > -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> > +void vgic_v3_clear_uie(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);
> > -
> > -			/* Only SPIs require notification */
> > -			if (vgic_valid_spi(vcpu->kvm, intid))
> > -				kvm_notify_acked_irq(vcpu->kvm, 0,
> > -						     intid - VGIC_NR_PRIVATE_IRQS);
> > -		}
> > -
> > -		/*
> > -		 * 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;
> >  }
> >  
> > @@ -67,6 +34,12 @@ void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> >  	cpuif->vgic_hcr |= ICH_HCR_UIE;
> >  }
> >  
> > +static bool lr_signals_eoi_mi(u64 lr_val)
> > +{
> > +	return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) &&
> > +	       !(lr_val & ICH_LR_HW);
> > +}
> > +
> >  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> >  {
> >  	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> > @@ -82,6 +55,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> >  			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> >  		else
> >  			intid = val & GICH_LR_VIRTUALID;
> > +
> > +		/* Notify fds when the guest EOI'ed a level-triggered IRQ */
> > +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> > +			kvm_notify_acked_irq(vcpu->kvm, 0,
> > +					     intid - VGIC_NR_PRIVATE_IRQS);
> > +
> >  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >  		if (!irq)	/* An LPI could have been unmapped. */
> >  			continue;
> > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > index 1436c2e..f5b3c25 100644
> > --- a/virt/kvm/arm/vgic/vgic.c
> > +++ b/virt/kvm/arm/vgic/vgic.c
> > @@ -527,12 +527,12 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> >  	spin_unlock(&vgic_cpu->ap_list_lock);
> >  }
> >  
> > -static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> > +static inline void vgic_clear_uie(struct kvm_vcpu *vcpu)
> >  {
> >  	if (kvm_vgic_global_state.type == VGIC_V2)
> > -		vgic_v2_process_maintenance(vcpu);
> > +		vgic_v2_clear_uie(vcpu);
> >  	else
> > -		vgic_v3_process_maintenance(vcpu);
> > +		vgic_v3_clear_uie(vcpu);
> >  }
> >  
> >  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> > @@ -642,7 +642,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> >  	if (unlikely(!vgic_initialized(vcpu->kvm)))
> >  		return;
> >  
> > -	vgic_process_maintenance_interrupt(vcpu);
> > +	vgic_clear_uie(vcpu);
> >  	vgic_fold_lr_state(vcpu);
> 
> nit: If you moved vgic_*_clear_uie() into vgic_*_fold_lr_state, you
> could get rid of this call, extra prototypes, and save yourself the
> extra check. Not a big deal though.
> 

I thought about this, but the problem is that strictly speaking, you
don't need to consume any LRs to set the underflow, you just need enough
in the AP list, and it's theoretically possible that you have nr_lrs+1
interrupts in the AP list which have all been migrated away.

So, it would require something like this including a rework in
flush_lr_state to work with the following patch which only calls
vgic_fold_lr_state when there are in fact anything live in LRs:

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index e5cf930..4b1feef 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -601,10 +601,8 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 
 	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
 
-	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
-		vgic_set_underflow(vcpu);
+	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr)
 		vgic_sort_ap_list(vcpu);
-	}
 
 	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
 		spin_lock(&irq->irq_lock);
@@ -623,8 +621,12 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 next:
 		spin_unlock(&irq->irq_lock);
 
-		if (count == kvm_vgic_global_state.nr_lr)
+		if (count == kvm_vgic_global_state.nr_lr) {
+			if (!list_is_last(&irq->ap_list,
+					  &vgic_cpu->ap_list_head))
+				vgic_set_underflow(vcpu);
 			break;
+		}
 	}
 
 	vcpu->arch.vgic_cpu.used_lrs = count;

What do you think?

> >  	vgic_prune_ap_list(vcpu);
> >  
> > diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> > index 3f64220..72ba9ee 100644
> > --- a/virt/kvm/arm/vgic/vgic.h
> > +++ b/virt/kvm/arm/vgic/vgic.h
> > @@ -112,7 +112,7 @@ void vgic_kick_vcpus(struct kvm *kvm);
> >  int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
> >  		      phys_addr_t addr, phys_addr_t alignment);
> >  
> > -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> > +void vgic_v2_clear_uie(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);
> > @@ -143,7 +143,7 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
> >  	kref_get(&irq->refcount);
> >  }
> >  
> > -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> > +void vgic_v3_clear_uie(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);
> > 
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operationjjjj
@ 2017-03-21 12:26       ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 12:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 21, 2017 at 11:36:19AM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > From: Christoffer Dall <christoffer.dall@linaro.org>
> > 
> > Since we always read back the LRs that we wrote to the guest and the
> > MISR and EISR registers simply provide a summary of the configuration of
> > the bits in the LRs, there is really no need to read back those status
> > registers and process them.  We can might as well just signal the
> > notifyfd when folding the LR state and save some cycles in the process.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  virt/kvm/arm/vgic/vgic-v2.c | 55 ++++++++++-----------------------------------
> >  virt/kvm/arm/vgic/vgic-v3.c | 47 +++++++++++---------------------------
> >  virt/kvm/arm/vgic/vgic.c    |  8 +++----
> >  virt/kvm/arm/vgic/vgic.h    |  4 ++--
> >  4 files changed, 31 insertions(+), 83 deletions(-)
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> > index dfe6e5e..0172754 100644
> > --- a/virt/kvm/arm/vgic/vgic-v2.c
> > +++ b/virt/kvm/arm/vgic/vgic-v2.c
> > @@ -22,20 +22,6 @@
> >  
> >  #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;
> > -}
> > -
> 
> Getting rid of u64_to_bitmask makes me feel slightly better...
> 
> >  static inline void vgic_v2_write_lr(int lr, u32 val)
> >  {
> >  	void __iomem *base = kvm_vgic_global_state.vctrl_base;
> > @@ -51,38 +37,10 @@ void vgic_v2_init_lrs(void)
> >  		vgic_v2_write_lr(i, 0);
> >  }
> >  
> > -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> > +void vgic_v2_clear_uie(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);
> > -
> > -			/* Only SPIs require notification */
> > -			if (vgic_valid_spi(vcpu->kvm, intid))
> > -				kvm_notify_acked_irq(vcpu->kvm, 0,
> > -						     intid - VGIC_NR_PRIVATE_IRQS);
> > -		}
> > -	}
> > -
> > -	/* 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)
> > @@ -92,6 +50,12 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> >  	cpuif->vgic_hcr |= GICH_HCR_UIE;
> >  }
> >  
> > +static bool lr_signals_eoi_mi(u32 lr_val)
> > +{
> > +	return !(lr_val & GICH_LR_STATE) && (lr_val & GICH_LR_EOI) &&
> > +	       !(lr_val & GICH_LR_HW);
> > +}
> > +
> >  /*
> >   * transfer the content of the LRs back into the corresponding ap_list:
> >   * - active bit is transferred as is
> > @@ -109,6 +73,11 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> >  		u32 intid = val & GICH_LR_VIRTUALID;
> >  		struct vgic_irq *irq;
> >  
> > +		/* Notify fds when the guest EOI'ed a level-triggered SPI */
> > +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> > +			kvm_notify_acked_irq(vcpu->kvm, 0,
> > +					     intid - VGIC_NR_PRIVATE_IRQS);
> > +
> >  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >  
> >  		spin_lock(&irq->irq_lock);
> > diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> > index 3d7796c..7880c5c 100644
> > --- a/virt/kvm/arm/vgic/vgic-v3.c
> > +++ b/virt/kvm/arm/vgic/vgic-v3.c
> > @@ -21,42 +21,9 @@
> >  
> >  #include "vgic.h"
> >  
> > -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> > +void vgic_v3_clear_uie(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);
> > -
> > -			/* Only SPIs require notification */
> > -			if (vgic_valid_spi(vcpu->kvm, intid))
> > -				kvm_notify_acked_irq(vcpu->kvm, 0,
> > -						     intid - VGIC_NR_PRIVATE_IRQS);
> > -		}
> > -
> > -		/*
> > -		 * 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;
> >  }
> >  
> > @@ -67,6 +34,12 @@ void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> >  	cpuif->vgic_hcr |= ICH_HCR_UIE;
> >  }
> >  
> > +static bool lr_signals_eoi_mi(u64 lr_val)
> > +{
> > +	return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) &&
> > +	       !(lr_val & ICH_LR_HW);
> > +}
> > +
> >  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> >  {
> >  	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> > @@ -82,6 +55,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> >  			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> >  		else
> >  			intid = val & GICH_LR_VIRTUALID;
> > +
> > +		/* Notify fds when the guest EOI'ed a level-triggered IRQ */
> > +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> > +			kvm_notify_acked_irq(vcpu->kvm, 0,
> > +					     intid - VGIC_NR_PRIVATE_IRQS);
> > +
> >  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >  		if (!irq)	/* An LPI could have been unmapped. */
> >  			continue;
> > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > index 1436c2e..f5b3c25 100644
> > --- a/virt/kvm/arm/vgic/vgic.c
> > +++ b/virt/kvm/arm/vgic/vgic.c
> > @@ -527,12 +527,12 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> >  	spin_unlock(&vgic_cpu->ap_list_lock);
> >  }
> >  
> > -static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> > +static inline void vgic_clear_uie(struct kvm_vcpu *vcpu)
> >  {
> >  	if (kvm_vgic_global_state.type == VGIC_V2)
> > -		vgic_v2_process_maintenance(vcpu);
> > +		vgic_v2_clear_uie(vcpu);
> >  	else
> > -		vgic_v3_process_maintenance(vcpu);
> > +		vgic_v3_clear_uie(vcpu);
> >  }
> >  
> >  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> > @@ -642,7 +642,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> >  	if (unlikely(!vgic_initialized(vcpu->kvm)))
> >  		return;
> >  
> > -	vgic_process_maintenance_interrupt(vcpu);
> > +	vgic_clear_uie(vcpu);
> >  	vgic_fold_lr_state(vcpu);
> 
> nit: If you moved vgic_*_clear_uie() into vgic_*_fold_lr_state, you
> could get rid of this call, extra prototypes, and save yourself the
> extra check. Not a big deal though.
> 

I thought about this, but the problem is that strictly speaking, you
don't need to consume any LRs to set the underflow, you just need enough
in the AP list, and it's theoretically possible that you have nr_lrs+1
interrupts in the AP list which have all been migrated away.

So, it would require something like this including a rework in
flush_lr_state to work with the following patch which only calls
vgic_fold_lr_state when there are in fact anything live in LRs:

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index e5cf930..4b1feef 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -601,10 +601,8 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 
 	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
 
-	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
-		vgic_set_underflow(vcpu);
+	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr)
 		vgic_sort_ap_list(vcpu);
-	}
 
 	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
 		spin_lock(&irq->irq_lock);
@@ -623,8 +621,12 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 next:
 		spin_unlock(&irq->irq_lock);
 
-		if (count == kvm_vgic_global_state.nr_lr)
+		if (count == kvm_vgic_global_state.nr_lr) {
+			if (!list_is_last(&irq->ap_list,
+					  &vgic_cpu->ap_list_head))
+				vgic_set_underflow(vcpu);
 			break;
+		}
 	}
 
 	vcpu->arch.vgic_cpu.used_lrs = count;

What do you think?

> >  	vgic_prune_ap_list(vcpu);
> >  
> > diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> > index 3f64220..72ba9ee 100644
> > --- a/virt/kvm/arm/vgic/vgic.h
> > +++ b/virt/kvm/arm/vgic/vgic.h
> > @@ -112,7 +112,7 @@ void vgic_kick_vcpus(struct kvm *kvm);
> >  int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
> >  		      phys_addr_t addr, phys_addr_t alignment);
> >  
> > -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> > +void vgic_v2_clear_uie(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);
> > @@ -143,7 +143,7 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
> >  	kref_get(&irq->refcount);
> >  }
> >  
> > -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> > +void vgic_v3_clear_uie(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);
> > 
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* Re: [PATCH 7/9] KVM: arm/arm64: vgic: Implement early VGIC init functionality
  2017-03-21 12:05     ` Marc Zyngier
@ 2017-03-21 12:29       ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 12:29 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: Andre Przywara, kvmarm, linux-arm-kernel, kvm

On Tue, Mar 21, 2017 at 12:05:30PM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > Implement early initialization for both the distributor and the CPU
> > interfaces.  The basic idea is that even though the VGIC is not
> > functional or not requested from user space, the critical path of the
> > run loop can still call VGIC functions that just won't do anything,
> > without them having to check additional initialization flags to ensure
> > they don't look at uninitialized data structures.
> > 
> > Signed-off-by: Christoffer Dall <cdall@linaro.org>
> > ---
> >  virt/kvm/arm/vgic/vgic-init.c | 96 +++++++++++++++++++++++++------------------
> >  1 file changed, 56 insertions(+), 40 deletions(-)
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> > index 3762fd1..25fd1b9 100644
> > --- a/virt/kvm/arm/vgic/vgic-init.c
> > +++ b/virt/kvm/arm/vgic/vgic-init.c
> > @@ -24,7 +24,12 @@
> >  
> >  /*
> >   * Initialization rules: there are multiple stages to the vgic
> > - * initialization, both for the distributor and the CPU interfaces.
> > + * initialization, both for the distributor and the CPU interfaces.  The basic
> > + * idea is that even though the VGIC is not functional or not requested from
> > + * user space, the critical path of the run loop can still call VGIC functions
> > + * that just won't do anything, without them having to check additional
> > + * initialization flags to ensure they don't look at uninitialized data
> > + * structures.
> >   *
> >   * Distributor:
> >   *
> > @@ -39,23 +44,67 @@
> >   *
> >   * CPU Interface:
> >   *
> > - * - kvm_vgic_cpu_early_init(): initialization of static data that
> > + * - kvm_vgic_vcpu_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
> > +/**
> > + * kvm_vgic_early_init() - Initialize static VGIC VCPU data structures
> > + * @kvm: The VM whose VGIC districutor should be initialized
> > + *
> > + * Only do initialization of static structures that don't require any
> > + * allocation or sizing information from userspace.  vgic_init() called
> > + * kvm_vgic_dist_init() which takes care of the rest.
> >   */
> >  void kvm_vgic_early_init(struct kvm *kvm)
> >  {
> > +	struct vgic_dist *dist = &kvm->arch.vgic;
> > +
> > +	INIT_LIST_HEAD(&dist->lpi_list_head);
> > +	spin_lock_init(&dist->lpi_list_lock);
> >  }
> >  
> > +/**
> > + * kvm_vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
> > + * @vcpu: The VCPU whose VGIC data structures whould be initialized
> > + *
> > + * Only do initialization, but do not actually enable the VGIC CPU interface
> > + * yet.
> > + */
> >  void kvm_vgic_vcpu_early_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;
> > +		kref_init(&irq->refcount);
> > +		if (vgic_irq_is_sgi(i)) {
> > +			/* SGIs */
> > +			irq->enabled = 1;
> > +			irq->config = VGIC_CONFIG_EDGE;
> > +		} else {
> > +			/* PPIs */
> > +			irq->config = VGIC_CONFIG_LEVEL;
> > +		}
> > +	}
> >  }
> >  
> >  /* CREATION */
> > @@ -148,9 +197,6 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
> >  	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
> >  	int i;
> >  
> > -	INIT_LIST_HEAD(&dist->lpi_list_head);
> > -	spin_lock_init(&dist->lpi_list_lock);
> > -
> >  	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
> >  	if (!dist->spis)
> >  		return  -ENOMEM;
> > @@ -181,41 +227,11 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
> >  }
> >  
> >  /**
> > - * kvm_vgic_vcpu_init: initialize the vcpu data structures and
> > - * enable the VCPU interface
> > - * @vcpu: the VCPU which's VGIC should be initialized
> > + * kvm_vgic_vcpu_init() - Enable the VCPU interface
> > + * @vcpu: the VCPU which's VGIC should be enabled
> >   */
> >  static 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;
> > -		kref_init(&irq->refcount);
> > -		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
> > 
> 
> Since this function is now about enabling the vgic on a given vcpu,
> shouldn't the name reflect this? Other than that:

The v3 version does something which is a bit of a mix between
initialization and enabling, plus it would add even more churn, so, meh,
not really sure.  If you feel it should be kvm_vgic_vcpu_enable(), I'm
okay with changing it.

> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* [PATCH 7/9] KVM: arm/arm64: vgic: Implement early VGIC init functionality
@ 2017-03-21 12:29       ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 12:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 21, 2017 at 12:05:30PM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > Implement early initialization for both the distributor and the CPU
> > interfaces.  The basic idea is that even though the VGIC is not
> > functional or not requested from user space, the critical path of the
> > run loop can still call VGIC functions that just won't do anything,
> > without them having to check additional initialization flags to ensure
> > they don't look at uninitialized data structures.
> > 
> > Signed-off-by: Christoffer Dall <cdall@linaro.org>
> > ---
> >  virt/kvm/arm/vgic/vgic-init.c | 96 +++++++++++++++++++++++++------------------
> >  1 file changed, 56 insertions(+), 40 deletions(-)
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> > index 3762fd1..25fd1b9 100644
> > --- a/virt/kvm/arm/vgic/vgic-init.c
> > +++ b/virt/kvm/arm/vgic/vgic-init.c
> > @@ -24,7 +24,12 @@
> >  
> >  /*
> >   * Initialization rules: there are multiple stages to the vgic
> > - * initialization, both for the distributor and the CPU interfaces.
> > + * initialization, both for the distributor and the CPU interfaces.  The basic
> > + * idea is that even though the VGIC is not functional or not requested from
> > + * user space, the critical path of the run loop can still call VGIC functions
> > + * that just won't do anything, without them having to check additional
> > + * initialization flags to ensure they don't look at uninitialized data
> > + * structures.
> >   *
> >   * Distributor:
> >   *
> > @@ -39,23 +44,67 @@
> >   *
> >   * CPU Interface:
> >   *
> > - * - kvm_vgic_cpu_early_init(): initialization of static data that
> > + * - kvm_vgic_vcpu_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
> > +/**
> > + * kvm_vgic_early_init() - Initialize static VGIC VCPU data structures
> > + * @kvm: The VM whose VGIC districutor should be initialized
> > + *
> > + * Only do initialization of static structures that don't require any
> > + * allocation or sizing information from userspace.  vgic_init() called
> > + * kvm_vgic_dist_init() which takes care of the rest.
> >   */
> >  void kvm_vgic_early_init(struct kvm *kvm)
> >  {
> > +	struct vgic_dist *dist = &kvm->arch.vgic;
> > +
> > +	INIT_LIST_HEAD(&dist->lpi_list_head);
> > +	spin_lock_init(&dist->lpi_list_lock);
> >  }
> >  
> > +/**
> > + * kvm_vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
> > + * @vcpu: The VCPU whose VGIC data structures whould be initialized
> > + *
> > + * Only do initialization, but do not actually enable the VGIC CPU interface
> > + * yet.
> > + */
> >  void kvm_vgic_vcpu_early_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;
> > +		kref_init(&irq->refcount);
> > +		if (vgic_irq_is_sgi(i)) {
> > +			/* SGIs */
> > +			irq->enabled = 1;
> > +			irq->config = VGIC_CONFIG_EDGE;
> > +		} else {
> > +			/* PPIs */
> > +			irq->config = VGIC_CONFIG_LEVEL;
> > +		}
> > +	}
> >  }
> >  
> >  /* CREATION */
> > @@ -148,9 +197,6 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
> >  	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
> >  	int i;
> >  
> > -	INIT_LIST_HEAD(&dist->lpi_list_head);
> > -	spin_lock_init(&dist->lpi_list_lock);
> > -
> >  	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
> >  	if (!dist->spis)
> >  		return  -ENOMEM;
> > @@ -181,41 +227,11 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
> >  }
> >  
> >  /**
> > - * kvm_vgic_vcpu_init: initialize the vcpu data structures and
> > - * enable the VCPU interface
> > - * @vcpu: the VCPU which's VGIC should be initialized
> > + * kvm_vgic_vcpu_init() - Enable the VCPU interface
> > + * @vcpu: the VCPU which's VGIC should be enabled
> >   */
> >  static 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;
> > -		kref_init(&irq->refcount);
> > -		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
> > 
> 
> Since this function is now about enabling the vgic on a given vcpu,
> shouldn't the name reflect this? Other than that:

The v3 version does something which is a bit of a mix between
initialization and enabling, plus it would add even more churn, so, meh,
not really sure.  If you feel it should be kvm_vgic_vcpu_enable(), I'm
okay with changing it.

> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* Re: [PATCH 8/9] KVM: arm/arm64: vgic: Don't check vgic_initialized in flush_hwstate
  2017-03-21 12:08     ` Marc Zyngier
@ 2017-03-21 12:30       ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 12:30 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: Andre Przywara, kvmarm, linux-arm-kernel, kvm

On Tue, Mar 21, 2017 at 12:08:15PM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > Now when we do an early init of the static parts of the VGIC data
> > structures, we can do things like checking if the AP lists are empty
> > directly without having to explicitly check if the vgic is initialized
> > and reduce a bit of work in our criticial path.
> 
>                                   critical
> 
> > Note: list_empty is a single atomic read (uses READ_ONCE) and can
> > therefore check if a list is empty or not without the need to take the
> > spinlock protecting the list.
> 
> This note might be better placed in patch #2.

Agreed.

> 
> > 
> > Signed-off-by: Christoffer Dall <cdall@linaro.org>
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* [PATCH 8/9] KVM: arm/arm64: vgic: Don't check vgic_initialized in flush_hwstate
@ 2017-03-21 12:30       ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 12:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 21, 2017 at 12:08:15PM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > Now when we do an early init of the static parts of the VGIC data
> > structures, we can do things like checking if the AP lists are empty
> > directly without having to explicitly check if the vgic is initialized
> > and reduce a bit of work in our criticial path.
> 
>                                   critical
> 
> > Note: list_empty is a single atomic read (uses READ_ONCE) and can
> > therefore check if a list is empty or not without the need to take the
> > spinlock protecting the list.
> 
> This note might be better placed in patch #2.

Agreed.

> 
> > 
> > Signed-off-by: Christoffer Dall <cdall@linaro.org>
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* Re: [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operationjjjj
  2017-03-21 12:26       ` Christoffer Dall
@ 2017-03-21 13:26         ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 13:26 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvmarm, linux-arm-kernel, kvm, Andre Przywara, Eric Auger,
	Christoffer Dall

On 21/03/17 12:26, Christoffer Dall wrote:
> On Tue, Mar 21, 2017 at 11:36:19AM +0000, Marc Zyngier wrote:
>> On 20/03/17 10:58, Christoffer Dall wrote:
>>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>>
>>> Since we always read back the LRs that we wrote to the guest and the
>>> MISR and EISR registers simply provide a summary of the configuration of
>>> the bits in the LRs, there is really no need to read back those status
>>> registers and process them.  We can might as well just signal the
>>> notifyfd when folding the LR state and save some cycles in the process.
>>>
>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>> ---
>>>  virt/kvm/arm/vgic/vgic-v2.c | 55 ++++++++++-----------------------------------
>>>  virt/kvm/arm/vgic/vgic-v3.c | 47 +++++++++++---------------------------
>>>  virt/kvm/arm/vgic/vgic.c    |  8 +++----
>>>  virt/kvm/arm/vgic/vgic.h    |  4 ++--
>>>  4 files changed, 31 insertions(+), 83 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>> index dfe6e5e..0172754 100644
>>> --- a/virt/kvm/arm/vgic/vgic-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>> @@ -22,20 +22,6 @@
>>>  
>>>  #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;
>>> -}
>>> -
>>
>> Getting rid of u64_to_bitmask makes me feel slightly better...
>>
>>>  static inline void vgic_v2_write_lr(int lr, u32 val)
>>>  {
>>>  	void __iomem *base = kvm_vgic_global_state.vctrl_base;
>>> @@ -51,38 +37,10 @@ void vgic_v2_init_lrs(void)
>>>  		vgic_v2_write_lr(i, 0);
>>>  }
>>>  
>>> -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>> +void vgic_v2_clear_uie(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);
>>> -
>>> -			/* Only SPIs require notification */
>>> -			if (vgic_valid_spi(vcpu->kvm, intid))
>>> -				kvm_notify_acked_irq(vcpu->kvm, 0,
>>> -						     intid - VGIC_NR_PRIVATE_IRQS);
>>> -		}
>>> -	}
>>> -
>>> -	/* 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)
>>> @@ -92,6 +50,12 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>>>  	cpuif->vgic_hcr |= GICH_HCR_UIE;
>>>  }
>>>  
>>> +static bool lr_signals_eoi_mi(u32 lr_val)
>>> +{
>>> +	return !(lr_val & GICH_LR_STATE) && (lr_val & GICH_LR_EOI) &&
>>> +	       !(lr_val & GICH_LR_HW);
>>> +}
>>> +
>>>  /*
>>>   * transfer the content of the LRs back into the corresponding ap_list:
>>>   * - active bit is transferred as is
>>> @@ -109,6 +73,11 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>>>  		u32 intid = val & GICH_LR_VIRTUALID;
>>>  		struct vgic_irq *irq;
>>>  
>>> +		/* Notify fds when the guest EOI'ed a level-triggered SPI */
>>> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>> +
>>>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>>>  
>>>  		spin_lock(&irq->irq_lock);
>>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>>> index 3d7796c..7880c5c 100644
>>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>>> @@ -21,42 +21,9 @@
>>>  
>>>  #include "vgic.h"
>>>  
>>> -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>>> +void vgic_v3_clear_uie(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);
>>> -
>>> -			/* Only SPIs require notification */
>>> -			if (vgic_valid_spi(vcpu->kvm, intid))
>>> -				kvm_notify_acked_irq(vcpu->kvm, 0,
>>> -						     intid - VGIC_NR_PRIVATE_IRQS);
>>> -		}
>>> -
>>> -		/*
>>> -		 * 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;
>>>  }
>>>  
>>> @@ -67,6 +34,12 @@ void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>>>  	cpuif->vgic_hcr |= ICH_HCR_UIE;
>>>  }
>>>  
>>> +static bool lr_signals_eoi_mi(u64 lr_val)
>>> +{
>>> +	return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) &&
>>> +	       !(lr_val & ICH_LR_HW);
>>> +}
>>> +
>>>  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>>>  {
>>>  	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>>> @@ -82,6 +55,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>>>  			intid = val & ICH_LR_VIRTUAL_ID_MASK;
>>>  		else
>>>  			intid = val & GICH_LR_VIRTUALID;
>>> +
>>> +		/* Notify fds when the guest EOI'ed a level-triggered IRQ */
>>> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>> +
>>>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>>>  		if (!irq)	/* An LPI could have been unmapped. */
>>>  			continue;
>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>>> index 1436c2e..f5b3c25 100644
>>> --- a/virt/kvm/arm/vgic/vgic.c
>>> +++ b/virt/kvm/arm/vgic/vgic.c
>>> @@ -527,12 +527,12 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
>>>  	spin_unlock(&vgic_cpu->ap_list_lock);
>>>  }
>>>  
>>> -static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>>> +static inline void vgic_clear_uie(struct kvm_vcpu *vcpu)
>>>  {
>>>  	if (kvm_vgic_global_state.type == VGIC_V2)
>>> -		vgic_v2_process_maintenance(vcpu);
>>> +		vgic_v2_clear_uie(vcpu);
>>>  	else
>>> -		vgic_v3_process_maintenance(vcpu);
>>> +		vgic_v3_clear_uie(vcpu);
>>>  }
>>>  
>>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>>> @@ -642,7 +642,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>>>  	if (unlikely(!vgic_initialized(vcpu->kvm)))
>>>  		return;
>>>  
>>> -	vgic_process_maintenance_interrupt(vcpu);
>>> +	vgic_clear_uie(vcpu);
>>>  	vgic_fold_lr_state(vcpu);
>>
>> nit: If you moved vgic_*_clear_uie() into vgic_*_fold_lr_state, you
>> could get rid of this call, extra prototypes, and save yourself the
>> extra check. Not a big deal though.
>>
> 
> I thought about this, but the problem is that strictly speaking, you
> don't need to consume any LRs to set the underflow, you just need enough
> in the AP list, and it's theoretically possible that you have nr_lrs+1
> interrupts in the AP list which have all been migrated away.

But isn't that a problem we already have, independently of reworking the
above?

> So, it would require something like this including a rework in
> flush_lr_state to work with the following patch which only calls
> vgic_fold_lr_state when there are in fact anything live in LRs:
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index e5cf930..4b1feef 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -601,10 +601,8 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
>  
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
>  
> -	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> -		vgic_set_underflow(vcpu);
> +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr)
>  		vgic_sort_ap_list(vcpu);
> -	}
>  
>  	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
>  		spin_lock(&irq->irq_lock);
> @@ -623,8 +621,12 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
>  next:
>  		spin_unlock(&irq->irq_lock);
>  
> -		if (count == kvm_vgic_global_state.nr_lr)
> +		if (count == kvm_vgic_global_state.nr_lr) {
> +			if (!list_is_last(&irq->ap_list,
> +					  &vgic_cpu->ap_list_head))
> +				vgic_set_underflow(vcpu);
>  			break;
> +		}
>  	}
>  
>  	vcpu->arch.vgic_cpu.used_lrs = count;
> 
> What do you think?

I think this deserves a patch of its own. Also, how about renaming
clear_uie to clear_underflow?

Thanks,

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

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

* [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operationjjjj
@ 2017-03-21 13:26         ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 13:26 UTC (permalink / raw)
  To: linux-arm-kernel

On 21/03/17 12:26, Christoffer Dall wrote:
> On Tue, Mar 21, 2017 at 11:36:19AM +0000, Marc Zyngier wrote:
>> On 20/03/17 10:58, Christoffer Dall wrote:
>>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>>
>>> Since we always read back the LRs that we wrote to the guest and the
>>> MISR and EISR registers simply provide a summary of the configuration of
>>> the bits in the LRs, there is really no need to read back those status
>>> registers and process them.  We can might as well just signal the
>>> notifyfd when folding the LR state and save some cycles in the process.
>>>
>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>> ---
>>>  virt/kvm/arm/vgic/vgic-v2.c | 55 ++++++++++-----------------------------------
>>>  virt/kvm/arm/vgic/vgic-v3.c | 47 +++++++++++---------------------------
>>>  virt/kvm/arm/vgic/vgic.c    |  8 +++----
>>>  virt/kvm/arm/vgic/vgic.h    |  4 ++--
>>>  4 files changed, 31 insertions(+), 83 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>> index dfe6e5e..0172754 100644
>>> --- a/virt/kvm/arm/vgic/vgic-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>> @@ -22,20 +22,6 @@
>>>  
>>>  #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;
>>> -}
>>> -
>>
>> Getting rid of u64_to_bitmask makes me feel slightly better...
>>
>>>  static inline void vgic_v2_write_lr(int lr, u32 val)
>>>  {
>>>  	void __iomem *base = kvm_vgic_global_state.vctrl_base;
>>> @@ -51,38 +37,10 @@ void vgic_v2_init_lrs(void)
>>>  		vgic_v2_write_lr(i, 0);
>>>  }
>>>  
>>> -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>> +void vgic_v2_clear_uie(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);
>>> -
>>> -			/* Only SPIs require notification */
>>> -			if (vgic_valid_spi(vcpu->kvm, intid))
>>> -				kvm_notify_acked_irq(vcpu->kvm, 0,
>>> -						     intid - VGIC_NR_PRIVATE_IRQS);
>>> -		}
>>> -	}
>>> -
>>> -	/* 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)
>>> @@ -92,6 +50,12 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>>>  	cpuif->vgic_hcr |= GICH_HCR_UIE;
>>>  }
>>>  
>>> +static bool lr_signals_eoi_mi(u32 lr_val)
>>> +{
>>> +	return !(lr_val & GICH_LR_STATE) && (lr_val & GICH_LR_EOI) &&
>>> +	       !(lr_val & GICH_LR_HW);
>>> +}
>>> +
>>>  /*
>>>   * transfer the content of the LRs back into the corresponding ap_list:
>>>   * - active bit is transferred as is
>>> @@ -109,6 +73,11 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>>>  		u32 intid = val & GICH_LR_VIRTUALID;
>>>  		struct vgic_irq *irq;
>>>  
>>> +		/* Notify fds when the guest EOI'ed a level-triggered SPI */
>>> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>> +
>>>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>>>  
>>>  		spin_lock(&irq->irq_lock);
>>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>>> index 3d7796c..7880c5c 100644
>>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>>> @@ -21,42 +21,9 @@
>>>  
>>>  #include "vgic.h"
>>>  
>>> -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>>> +void vgic_v3_clear_uie(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);
>>> -
>>> -			/* Only SPIs require notification */
>>> -			if (vgic_valid_spi(vcpu->kvm, intid))
>>> -				kvm_notify_acked_irq(vcpu->kvm, 0,
>>> -						     intid - VGIC_NR_PRIVATE_IRQS);
>>> -		}
>>> -
>>> -		/*
>>> -		 * 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;
>>>  }
>>>  
>>> @@ -67,6 +34,12 @@ void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>>>  	cpuif->vgic_hcr |= ICH_HCR_UIE;
>>>  }
>>>  
>>> +static bool lr_signals_eoi_mi(u64 lr_val)
>>> +{
>>> +	return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) &&
>>> +	       !(lr_val & ICH_LR_HW);
>>> +}
>>> +
>>>  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>>>  {
>>>  	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>>> @@ -82,6 +55,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>>>  			intid = val & ICH_LR_VIRTUAL_ID_MASK;
>>>  		else
>>>  			intid = val & GICH_LR_VIRTUALID;
>>> +
>>> +		/* Notify fds when the guest EOI'ed a level-triggered IRQ */
>>> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>> +
>>>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>>>  		if (!irq)	/* An LPI could have been unmapped. */
>>>  			continue;
>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>>> index 1436c2e..f5b3c25 100644
>>> --- a/virt/kvm/arm/vgic/vgic.c
>>> +++ b/virt/kvm/arm/vgic/vgic.c
>>> @@ -527,12 +527,12 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
>>>  	spin_unlock(&vgic_cpu->ap_list_lock);
>>>  }
>>>  
>>> -static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>>> +static inline void vgic_clear_uie(struct kvm_vcpu *vcpu)
>>>  {
>>>  	if (kvm_vgic_global_state.type == VGIC_V2)
>>> -		vgic_v2_process_maintenance(vcpu);
>>> +		vgic_v2_clear_uie(vcpu);
>>>  	else
>>> -		vgic_v3_process_maintenance(vcpu);
>>> +		vgic_v3_clear_uie(vcpu);
>>>  }
>>>  
>>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>>> @@ -642,7 +642,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>>>  	if (unlikely(!vgic_initialized(vcpu->kvm)))
>>>  		return;
>>>  
>>> -	vgic_process_maintenance_interrupt(vcpu);
>>> +	vgic_clear_uie(vcpu);
>>>  	vgic_fold_lr_state(vcpu);
>>
>> nit: If you moved vgic_*_clear_uie() into vgic_*_fold_lr_state, you
>> could get rid of this call, extra prototypes, and save yourself the
>> extra check. Not a big deal though.
>>
> 
> I thought about this, but the problem is that strictly speaking, you
> don't need to consume any LRs to set the underflow, you just need enough
> in the AP list, and it's theoretically possible that you have nr_lrs+1
> interrupts in the AP list which have all been migrated away.

But isn't that a problem we already have, independently of reworking the
above?

> So, it would require something like this including a rework in
> flush_lr_state to work with the following patch which only calls
> vgic_fold_lr_state when there are in fact anything live in LRs:
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index e5cf930..4b1feef 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -601,10 +601,8 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
>  
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
>  
> -	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> -		vgic_set_underflow(vcpu);
> +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr)
>  		vgic_sort_ap_list(vcpu);
> -	}
>  
>  	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
>  		spin_lock(&irq->irq_lock);
> @@ -623,8 +621,12 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
>  next:
>  		spin_unlock(&irq->irq_lock);
>  
> -		if (count == kvm_vgic_global_state.nr_lr)
> +		if (count == kvm_vgic_global_state.nr_lr) {
> +			if (!list_is_last(&irq->ap_list,
> +					  &vgic_cpu->ap_list_head))
> +				vgic_set_underflow(vcpu);
>  			break;
> +		}
>  	}
>  
>  	vcpu->arch.vgic_cpu.used_lrs = count;
> 
> What do you think?

I think this deserves a patch of its own. Also, how about renaming
clear_uie to clear_underflow?

Thanks,

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

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

* Re: [PATCH 9/9] KVM: arm/arm64: vgic: Improve sync_hwstate performance
  2017-03-20 10:58   ` Christoffer Dall
@ 2017-03-21 13:29     ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 13:29 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel; +Cc: Andre Przywara, kvm

On 20/03/17 10:58, Christoffer Dall wrote:
> There is no need to call any functions to fold LRs when we don't use any
> LRs and we don't need to mess with overflow flags, take spinlocks, or
> prune the AP list if the AP list is empty.
> 
> Note: list_empty is a single atomic read (uses READ_ONCE) and can
> therefore check if a list is empty or not without the need to take the
> spinlock protecting the list.
> 
> Signed-off-by: Christoffer Dall <cdall@linaro.org>
> ---
>  virt/kvm/arm/vgic/vgic.c | 13 ++++++++-----
>  1 file changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 093873e..8ecb009 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -639,15 +639,18 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>  {
>  	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>  
> -	if (unlikely(!vgic_initialized(vcpu->kvm)))

Could this be folded with the previous patch? It is the same optimisation.

> +	/* An empty ap_list_head implies used_lrs == 0 */
> +	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
>  		return;
>  
>  	vgic_clear_uie(vcpu);
> -	vgic_fold_lr_state(vcpu);
> -	vgic_prune_ap_list(vcpu);
>  
> -	/* Make sure we can fast-path in flush_hwstate */
> -	vgic_cpu->used_lrs = 0;
> +	if (vgic_cpu->used_lrs) {
> +		vgic_fold_lr_state(vcpu);
> +		vgic_cpu->used_lrs = 0;

This zeroing could also be moved to vgic_fold_lr_state(), though I don't
feel strongly about it.

> +	}
> +
> +	vgic_prune_ap_list(vcpu);
>  }
>  
>  /* Flush our emulation state into the GIC hardware before entering the guest. */
> 

Otherwise looks good to me.

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

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

* [PATCH 9/9] KVM: arm/arm64: vgic: Improve sync_hwstate performance
@ 2017-03-21 13:29     ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 13:29 UTC (permalink / raw)
  To: linux-arm-kernel

On 20/03/17 10:58, Christoffer Dall wrote:
> There is no need to call any functions to fold LRs when we don't use any
> LRs and we don't need to mess with overflow flags, take spinlocks, or
> prune the AP list if the AP list is empty.
> 
> Note: list_empty is a single atomic read (uses READ_ONCE) and can
> therefore check if a list is empty or not without the need to take the
> spinlock protecting the list.
> 
> Signed-off-by: Christoffer Dall <cdall@linaro.org>
> ---
>  virt/kvm/arm/vgic/vgic.c | 13 ++++++++-----
>  1 file changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 093873e..8ecb009 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -639,15 +639,18 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
>  {
>  	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>  
> -	if (unlikely(!vgic_initialized(vcpu->kvm)))

Could this be folded with the previous patch? It is the same optimisation.

> +	/* An empty ap_list_head implies used_lrs == 0 */
> +	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
>  		return;
>  
>  	vgic_clear_uie(vcpu);
> -	vgic_fold_lr_state(vcpu);
> -	vgic_prune_ap_list(vcpu);
>  
> -	/* Make sure we can fast-path in flush_hwstate */
> -	vgic_cpu->used_lrs = 0;
> +	if (vgic_cpu->used_lrs) {
> +		vgic_fold_lr_state(vcpu);
> +		vgic_cpu->used_lrs = 0;

This zeroing could also be moved to vgic_fold_lr_state(), though I don't
feel strongly about it.

> +	}
> +
> +	vgic_prune_ap_list(vcpu);
>  }
>  
>  /* Flush our emulation state into the GIC hardware before entering the guest. */
> 

Otherwise looks good to me.

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

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

* Re: [PATCH 7/9] KVM: arm/arm64: vgic: Implement early VGIC init functionality
  2017-03-21 12:29       ` Christoffer Dall
@ 2017-03-21 13:30         ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 13:30 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvmarm, linux-arm-kernel, kvm, Andre Przywara, Eric Auger

On 21/03/17 12:29, Christoffer Dall wrote:
> On Tue, Mar 21, 2017 at 12:05:30PM +0000, Marc Zyngier wrote:
>> On 20/03/17 10:58, Christoffer Dall wrote:
>>> Implement early initialization for both the distributor and the CPU
>>> interfaces.  The basic idea is that even though the VGIC is not
>>> functional or not requested from user space, the critical path of the
>>> run loop can still call VGIC functions that just won't do anything,
>>> without them having to check additional initialization flags to ensure
>>> they don't look at uninitialized data structures.
>>>
>>> Signed-off-by: Christoffer Dall <cdall@linaro.org>
>>> ---
>>>  virt/kvm/arm/vgic/vgic-init.c | 96 +++++++++++++++++++++++++------------------
>>>  1 file changed, 56 insertions(+), 40 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
>>> index 3762fd1..25fd1b9 100644
>>> --- a/virt/kvm/arm/vgic/vgic-init.c
>>> +++ b/virt/kvm/arm/vgic/vgic-init.c
>>> @@ -24,7 +24,12 @@
>>>  
>>>  /*
>>>   * Initialization rules: there are multiple stages to the vgic
>>> - * initialization, both for the distributor and the CPU interfaces.
>>> + * initialization, both for the distributor and the CPU interfaces.  The basic
>>> + * idea is that even though the VGIC is not functional or not requested from
>>> + * user space, the critical path of the run loop can still call VGIC functions
>>> + * that just won't do anything, without them having to check additional
>>> + * initialization flags to ensure they don't look at uninitialized data
>>> + * structures.
>>>   *
>>>   * Distributor:
>>>   *
>>> @@ -39,23 +44,67 @@
>>>   *
>>>   * CPU Interface:
>>>   *
>>> - * - kvm_vgic_cpu_early_init(): initialization of static data that
>>> + * - kvm_vgic_vcpu_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
>>> +/**
>>> + * kvm_vgic_early_init() - Initialize static VGIC VCPU data structures
>>> + * @kvm: The VM whose VGIC districutor should be initialized
>>> + *
>>> + * Only do initialization of static structures that don't require any
>>> + * allocation or sizing information from userspace.  vgic_init() called
>>> + * kvm_vgic_dist_init() which takes care of the rest.
>>>   */
>>>  void kvm_vgic_early_init(struct kvm *kvm)
>>>  {
>>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>>> +
>>> +	INIT_LIST_HEAD(&dist->lpi_list_head);
>>> +	spin_lock_init(&dist->lpi_list_lock);
>>>  }
>>>  
>>> +/**
>>> + * kvm_vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
>>> + * @vcpu: The VCPU whose VGIC data structures whould be initialized
>>> + *
>>> + * Only do initialization, but do not actually enable the VGIC CPU interface
>>> + * yet.
>>> + */
>>>  void kvm_vgic_vcpu_early_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;
>>> +		kref_init(&irq->refcount);
>>> +		if (vgic_irq_is_sgi(i)) {
>>> +			/* SGIs */
>>> +			irq->enabled = 1;
>>> +			irq->config = VGIC_CONFIG_EDGE;
>>> +		} else {
>>> +			/* PPIs */
>>> +			irq->config = VGIC_CONFIG_LEVEL;
>>> +		}
>>> +	}
>>>  }
>>>  
>>>  /* CREATION */
>>> @@ -148,9 +197,6 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
>>>  	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
>>>  	int i;
>>>  
>>> -	INIT_LIST_HEAD(&dist->lpi_list_head);
>>> -	spin_lock_init(&dist->lpi_list_lock);
>>> -
>>>  	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
>>>  	if (!dist->spis)
>>>  		return  -ENOMEM;
>>> @@ -181,41 +227,11 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
>>>  }
>>>  
>>>  /**
>>> - * kvm_vgic_vcpu_init: initialize the vcpu data structures and
>>> - * enable the VCPU interface
>>> - * @vcpu: the VCPU which's VGIC should be initialized
>>> + * kvm_vgic_vcpu_init() - Enable the VCPU interface
>>> + * @vcpu: the VCPU which's VGIC should be enabled
>>>   */
>>>  static 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;
>>> -		kref_init(&irq->refcount);
>>> -		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
>>>
>>
>> Since this function is now about enabling the vgic on a given vcpu,
>> shouldn't the name reflect this? Other than that:
> 
> The v3 version does something which is a bit of a mix between
> initialization and enabling, plus it would add even more churn, so, meh,
> not really sure.  If you feel it should be kvm_vgic_vcpu_enable(), I'm
> okay with changing it.

Ah, indeed, this is a slightly busier function. Never mind.

Thanks,

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

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

* [PATCH 7/9] KVM: arm/arm64: vgic: Implement early VGIC init functionality
@ 2017-03-21 13:30         ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2017-03-21 13:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 21/03/17 12:29, Christoffer Dall wrote:
> On Tue, Mar 21, 2017 at 12:05:30PM +0000, Marc Zyngier wrote:
>> On 20/03/17 10:58, Christoffer Dall wrote:
>>> Implement early initialization for both the distributor and the CPU
>>> interfaces.  The basic idea is that even though the VGIC is not
>>> functional or not requested from user space, the critical path of the
>>> run loop can still call VGIC functions that just won't do anything,
>>> without them having to check additional initialization flags to ensure
>>> they don't look at uninitialized data structures.
>>>
>>> Signed-off-by: Christoffer Dall <cdall@linaro.org>
>>> ---
>>>  virt/kvm/arm/vgic/vgic-init.c | 96 +++++++++++++++++++++++++------------------
>>>  1 file changed, 56 insertions(+), 40 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
>>> index 3762fd1..25fd1b9 100644
>>> --- a/virt/kvm/arm/vgic/vgic-init.c
>>> +++ b/virt/kvm/arm/vgic/vgic-init.c
>>> @@ -24,7 +24,12 @@
>>>  
>>>  /*
>>>   * Initialization rules: there are multiple stages to the vgic
>>> - * initialization, both for the distributor and the CPU interfaces.
>>> + * initialization, both for the distributor and the CPU interfaces.  The basic
>>> + * idea is that even though the VGIC is not functional or not requested from
>>> + * user space, the critical path of the run loop can still call VGIC functions
>>> + * that just won't do anything, without them having to check additional
>>> + * initialization flags to ensure they don't look at uninitialized data
>>> + * structures.
>>>   *
>>>   * Distributor:
>>>   *
>>> @@ -39,23 +44,67 @@
>>>   *
>>>   * CPU Interface:
>>>   *
>>> - * - kvm_vgic_cpu_early_init(): initialization of static data that
>>> + * - kvm_vgic_vcpu_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
>>> +/**
>>> + * kvm_vgic_early_init() - Initialize static VGIC VCPU data structures
>>> + * @kvm: The VM whose VGIC districutor should be initialized
>>> + *
>>> + * Only do initialization of static structures that don't require any
>>> + * allocation or sizing information from userspace.  vgic_init() called
>>> + * kvm_vgic_dist_init() which takes care of the rest.
>>>   */
>>>  void kvm_vgic_early_init(struct kvm *kvm)
>>>  {
>>> +	struct vgic_dist *dist = &kvm->arch.vgic;
>>> +
>>> +	INIT_LIST_HEAD(&dist->lpi_list_head);
>>> +	spin_lock_init(&dist->lpi_list_lock);
>>>  }
>>>  
>>> +/**
>>> + * kvm_vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
>>> + * @vcpu: The VCPU whose VGIC data structures whould be initialized
>>> + *
>>> + * Only do initialization, but do not actually enable the VGIC CPU interface
>>> + * yet.
>>> + */
>>>  void kvm_vgic_vcpu_early_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;
>>> +		kref_init(&irq->refcount);
>>> +		if (vgic_irq_is_sgi(i)) {
>>> +			/* SGIs */
>>> +			irq->enabled = 1;
>>> +			irq->config = VGIC_CONFIG_EDGE;
>>> +		} else {
>>> +			/* PPIs */
>>> +			irq->config = VGIC_CONFIG_LEVEL;
>>> +		}
>>> +	}
>>>  }
>>>  
>>>  /* CREATION */
>>> @@ -148,9 +197,6 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
>>>  	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
>>>  	int i;
>>>  
>>> -	INIT_LIST_HEAD(&dist->lpi_list_head);
>>> -	spin_lock_init(&dist->lpi_list_lock);
>>> -
>>>  	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
>>>  	if (!dist->spis)
>>>  		return  -ENOMEM;
>>> @@ -181,41 +227,11 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
>>>  }
>>>  
>>>  /**
>>> - * kvm_vgic_vcpu_init: initialize the vcpu data structures and
>>> - * enable the VCPU interface
>>> - * @vcpu: the VCPU which's VGIC should be initialized
>>> + * kvm_vgic_vcpu_init() - Enable the VCPU interface
>>> + * @vcpu: the VCPU which's VGIC should be enabled
>>>   */
>>>  static 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;
>>> -		kref_init(&irq->refcount);
>>> -		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
>>>
>>
>> Since this function is now about enabling the vgic on a given vcpu,
>> shouldn't the name reflect this? Other than that:
> 
> The v3 version does something which is a bit of a mix between
> initialization and enabling, plus it would add even more churn, so, meh,
> not really sure.  If you feel it should be kvm_vgic_vcpu_enable(), I'm
> okay with changing it.

Ah, indeed, this is a slightly busier function. Never mind.

Thanks,

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

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

* Re: [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operationjjjj
  2017-03-21 13:26         ` Marc Zyngier
@ 2017-03-21 14:10           ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 14:10 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, Andre Przywara, linux-arm-kernel, kvmarm

On Tue, Mar 21, 2017 at 01:26:52PM +0000, Marc Zyngier wrote:
> On 21/03/17 12:26, Christoffer Dall wrote:
> > On Tue, Mar 21, 2017 at 11:36:19AM +0000, Marc Zyngier wrote:
> >> On 20/03/17 10:58, Christoffer Dall wrote:
> >>> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>>
> >>> Since we always read back the LRs that we wrote to the guest and the
> >>> MISR and EISR registers simply provide a summary of the configuration of
> >>> the bits in the LRs, there is really no need to read back those status
> >>> registers and process them.  We can might as well just signal the
> >>> notifyfd when folding the LR state and save some cycles in the process.
> >>>
> >>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >>> ---
> >>>  virt/kvm/arm/vgic/vgic-v2.c | 55 ++++++++++-----------------------------------
> >>>  virt/kvm/arm/vgic/vgic-v3.c | 47 +++++++++++---------------------------
> >>>  virt/kvm/arm/vgic/vgic.c    |  8 +++----
> >>>  virt/kvm/arm/vgic/vgic.h    |  4 ++--
> >>>  4 files changed, 31 insertions(+), 83 deletions(-)
> >>>
> >>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >>> index dfe6e5e..0172754 100644
> >>> --- a/virt/kvm/arm/vgic/vgic-v2.c
> >>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >>> @@ -22,20 +22,6 @@
> >>>  
> >>>  #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;
> >>> -}
> >>> -
> >>
> >> Getting rid of u64_to_bitmask makes me feel slightly better...
> >>
> >>>  static inline void vgic_v2_write_lr(int lr, u32 val)
> >>>  {
> >>>  	void __iomem *base = kvm_vgic_global_state.vctrl_base;
> >>> @@ -51,38 +37,10 @@ void vgic_v2_init_lrs(void)
> >>>  		vgic_v2_write_lr(i, 0);
> >>>  }
> >>>  
> >>> -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >>> +void vgic_v2_clear_uie(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);
> >>> -
> >>> -			/* Only SPIs require notification */
> >>> -			if (vgic_valid_spi(vcpu->kvm, intid))
> >>> -				kvm_notify_acked_irq(vcpu->kvm, 0,
> >>> -						     intid - VGIC_NR_PRIVATE_IRQS);
> >>> -		}
> >>> -	}
> >>> -
> >>> -	/* 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)
> >>> @@ -92,6 +50,12 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> >>>  	cpuif->vgic_hcr |= GICH_HCR_UIE;
> >>>  }
> >>>  
> >>> +static bool lr_signals_eoi_mi(u32 lr_val)
> >>> +{
> >>> +	return !(lr_val & GICH_LR_STATE) && (lr_val & GICH_LR_EOI) &&
> >>> +	       !(lr_val & GICH_LR_HW);
> >>> +}
> >>> +
> >>>  /*
> >>>   * transfer the content of the LRs back into the corresponding ap_list:
> >>>   * - active bit is transferred as is
> >>> @@ -109,6 +73,11 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> >>>  		u32 intid = val & GICH_LR_VIRTUALID;
> >>>  		struct vgic_irq *irq;
> >>>  
> >>> +		/* Notify fds when the guest EOI'ed a level-triggered SPI */
> >>> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> >>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >>> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >>> +
> >>>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >>>  
> >>>  		spin_lock(&irq->irq_lock);
> >>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> >>> index 3d7796c..7880c5c 100644
> >>> --- a/virt/kvm/arm/vgic/vgic-v3.c
> >>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> >>> @@ -21,42 +21,9 @@
> >>>  
> >>>  #include "vgic.h"
> >>>  
> >>> -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> >>> +void vgic_v3_clear_uie(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);
> >>> -
> >>> -			/* Only SPIs require notification */
> >>> -			if (vgic_valid_spi(vcpu->kvm, intid))
> >>> -				kvm_notify_acked_irq(vcpu->kvm, 0,
> >>> -						     intid - VGIC_NR_PRIVATE_IRQS);
> >>> -		}
> >>> -
> >>> -		/*
> >>> -		 * 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;
> >>>  }
> >>>  
> >>> @@ -67,6 +34,12 @@ void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> >>>  	cpuif->vgic_hcr |= ICH_HCR_UIE;
> >>>  }
> >>>  
> >>> +static bool lr_signals_eoi_mi(u64 lr_val)
> >>> +{
> >>> +	return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) &&
> >>> +	       !(lr_val & ICH_LR_HW);
> >>> +}
> >>> +
> >>>  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> >>>  {
> >>>  	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> >>> @@ -82,6 +55,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> >>>  			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> >>>  		else
> >>>  			intid = val & GICH_LR_VIRTUALID;
> >>> +
> >>> +		/* Notify fds when the guest EOI'ed a level-triggered IRQ */
> >>> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> >>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >>> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >>> +
> >>>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >>>  		if (!irq)	/* An LPI could have been unmapped. */
> >>>  			continue;
> >>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> >>> index 1436c2e..f5b3c25 100644
> >>> --- a/virt/kvm/arm/vgic/vgic.c
> >>> +++ b/virt/kvm/arm/vgic/vgic.c
> >>> @@ -527,12 +527,12 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> >>>  	spin_unlock(&vgic_cpu->ap_list_lock);
> >>>  }
> >>>  
> >>> -static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> >>> +static inline void vgic_clear_uie(struct kvm_vcpu *vcpu)
> >>>  {
> >>>  	if (kvm_vgic_global_state.type == VGIC_V2)
> >>> -		vgic_v2_process_maintenance(vcpu);
> >>> +		vgic_v2_clear_uie(vcpu);
> >>>  	else
> >>> -		vgic_v3_process_maintenance(vcpu);
> >>> +		vgic_v3_clear_uie(vcpu);
> >>>  }
> >>>  
> >>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> >>> @@ -642,7 +642,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> >>>  	if (unlikely(!vgic_initialized(vcpu->kvm)))
> >>>  		return;
> >>>  
> >>> -	vgic_process_maintenance_interrupt(vcpu);
> >>> +	vgic_clear_uie(vcpu);
> >>>  	vgic_fold_lr_state(vcpu);
> >>
> >> nit: If you moved vgic_*_clear_uie() into vgic_*_fold_lr_state, you
> >> could get rid of this call, extra prototypes, and save yourself the
> >> extra check. Not a big deal though.
> >>
> > 
> > I thought about this, but the problem is that strictly speaking, you
> > don't need to consume any LRs to set the underflow, you just need enough
> > in the AP list, and it's theoretically possible that you have nr_lrs+1
> > interrupts in the AP list which have all been migrated away.
> 
> But isn't that a problem we already have, independently of reworking the
> above?
> 

Sort of, but it doesn't really hurt anyone, because we currently always
clear the underflow bit unconditionally, so worst case, you'll take an
additional exit.

After I introduce the conditionals on the sync side, you could loop
forever between KVM/VM.

> > So, it would require something like this including a rework in
> > flush_lr_state to work with the following patch which only calls
> > vgic_fold_lr_state when there are in fact anything live in LRs:
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > index e5cf930..4b1feef 100644
> > --- a/virt/kvm/arm/vgic/vgic.c
> > +++ b/virt/kvm/arm/vgic/vgic.c
> > @@ -601,10 +601,8 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> >  
> >  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> >  
> > -	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> > -		vgic_set_underflow(vcpu);
> > +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr)
> >  		vgic_sort_ap_list(vcpu);
> > -	}
> >  
> >  	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> >  		spin_lock(&irq->irq_lock);
> > @@ -623,8 +621,12 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> >  next:
> >  		spin_unlock(&irq->irq_lock);
> >  
> > -		if (count == kvm_vgic_global_state.nr_lr)
> > +		if (count == kvm_vgic_global_state.nr_lr) {
> > +			if (!list_is_last(&irq->ap_list,
> > +					  &vgic_cpu->ap_list_head))
> > +				vgic_set_underflow(vcpu);
> >  			break;
> > +		}
> >  	}
> >  
> >  	vcpu->arch.vgic_cpu.used_lrs = count;
> > 
> > What do you think?
> 
> I think this deserves a patch of its own. Also, how about renaming
> clear_uie to clear_underflow?
> 
Fair enough, I can add this.

Thanks,
-Christoffer

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

* [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operationjjjj
@ 2017-03-21 14:10           ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 21, 2017 at 01:26:52PM +0000, Marc Zyngier wrote:
> On 21/03/17 12:26, Christoffer Dall wrote:
> > On Tue, Mar 21, 2017 at 11:36:19AM +0000, Marc Zyngier wrote:
> >> On 20/03/17 10:58, Christoffer Dall wrote:
> >>> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>>
> >>> Since we always read back the LRs that we wrote to the guest and the
> >>> MISR and EISR registers simply provide a summary of the configuration of
> >>> the bits in the LRs, there is really no need to read back those status
> >>> registers and process them.  We can might as well just signal the
> >>> notifyfd when folding the LR state and save some cycles in the process.
> >>>
> >>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >>> ---
> >>>  virt/kvm/arm/vgic/vgic-v2.c | 55 ++++++++++-----------------------------------
> >>>  virt/kvm/arm/vgic/vgic-v3.c | 47 +++++++++++---------------------------
> >>>  virt/kvm/arm/vgic/vgic.c    |  8 +++----
> >>>  virt/kvm/arm/vgic/vgic.h    |  4 ++--
> >>>  4 files changed, 31 insertions(+), 83 deletions(-)
> >>>
> >>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >>> index dfe6e5e..0172754 100644
> >>> --- a/virt/kvm/arm/vgic/vgic-v2.c
> >>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >>> @@ -22,20 +22,6 @@
> >>>  
> >>>  #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;
> >>> -}
> >>> -
> >>
> >> Getting rid of u64_to_bitmask makes me feel slightly better...
> >>
> >>>  static inline void vgic_v2_write_lr(int lr, u32 val)
> >>>  {
> >>>  	void __iomem *base = kvm_vgic_global_state.vctrl_base;
> >>> @@ -51,38 +37,10 @@ void vgic_v2_init_lrs(void)
> >>>  		vgic_v2_write_lr(i, 0);
> >>>  }
> >>>  
> >>> -void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >>> +void vgic_v2_clear_uie(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);
> >>> -
> >>> -			/* Only SPIs require notification */
> >>> -			if (vgic_valid_spi(vcpu->kvm, intid))
> >>> -				kvm_notify_acked_irq(vcpu->kvm, 0,
> >>> -						     intid - VGIC_NR_PRIVATE_IRQS);
> >>> -		}
> >>> -	}
> >>> -
> >>> -	/* 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)
> >>> @@ -92,6 +50,12 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> >>>  	cpuif->vgic_hcr |= GICH_HCR_UIE;
> >>>  }
> >>>  
> >>> +static bool lr_signals_eoi_mi(u32 lr_val)
> >>> +{
> >>> +	return !(lr_val & GICH_LR_STATE) && (lr_val & GICH_LR_EOI) &&
> >>> +	       !(lr_val & GICH_LR_HW);
> >>> +}
> >>> +
> >>>  /*
> >>>   * transfer the content of the LRs back into the corresponding ap_list:
> >>>   * - active bit is transferred as is
> >>> @@ -109,6 +73,11 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> >>>  		u32 intid = val & GICH_LR_VIRTUALID;
> >>>  		struct vgic_irq *irq;
> >>>  
> >>> +		/* Notify fds when the guest EOI'ed a level-triggered SPI */
> >>> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> >>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >>> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >>> +
> >>>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >>>  
> >>>  		spin_lock(&irq->irq_lock);
> >>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> >>> index 3d7796c..7880c5c 100644
> >>> --- a/virt/kvm/arm/vgic/vgic-v3.c
> >>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> >>> @@ -21,42 +21,9 @@
> >>>  
> >>>  #include "vgic.h"
> >>>  
> >>> -void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> >>> +void vgic_v3_clear_uie(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);
> >>> -
> >>> -			/* Only SPIs require notification */
> >>> -			if (vgic_valid_spi(vcpu->kvm, intid))
> >>> -				kvm_notify_acked_irq(vcpu->kvm, 0,
> >>> -						     intid - VGIC_NR_PRIVATE_IRQS);
> >>> -		}
> >>> -
> >>> -		/*
> >>> -		 * 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;
> >>>  }
> >>>  
> >>> @@ -67,6 +34,12 @@ void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> >>>  	cpuif->vgic_hcr |= ICH_HCR_UIE;
> >>>  }
> >>>  
> >>> +static bool lr_signals_eoi_mi(u64 lr_val)
> >>> +{
> >>> +	return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) &&
> >>> +	       !(lr_val & ICH_LR_HW);
> >>> +}
> >>> +
> >>>  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> >>>  {
> >>>  	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> >>> @@ -82,6 +55,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> >>>  			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> >>>  		else
> >>>  			intid = val & GICH_LR_VIRTUALID;
> >>> +
> >>> +		/* Notify fds when the guest EOI'ed a level-triggered IRQ */
> >>> +		if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
> >>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >>> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >>> +
> >>>  		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> >>>  		if (!irq)	/* An LPI could have been unmapped. */
> >>>  			continue;
> >>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> >>> index 1436c2e..f5b3c25 100644
> >>> --- a/virt/kvm/arm/vgic/vgic.c
> >>> +++ b/virt/kvm/arm/vgic/vgic.c
> >>> @@ -527,12 +527,12 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> >>>  	spin_unlock(&vgic_cpu->ap_list_lock);
> >>>  }
> >>>  
> >>> -static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> >>> +static inline void vgic_clear_uie(struct kvm_vcpu *vcpu)
> >>>  {
> >>>  	if (kvm_vgic_global_state.type == VGIC_V2)
> >>> -		vgic_v2_process_maintenance(vcpu);
> >>> +		vgic_v2_clear_uie(vcpu);
> >>>  	else
> >>> -		vgic_v3_process_maintenance(vcpu);
> >>> +		vgic_v3_clear_uie(vcpu);
> >>>  }
> >>>  
> >>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> >>> @@ -642,7 +642,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> >>>  	if (unlikely(!vgic_initialized(vcpu->kvm)))
> >>>  		return;
> >>>  
> >>> -	vgic_process_maintenance_interrupt(vcpu);
> >>> +	vgic_clear_uie(vcpu);
> >>>  	vgic_fold_lr_state(vcpu);
> >>
> >> nit: If you moved vgic_*_clear_uie() into vgic_*_fold_lr_state, you
> >> could get rid of this call, extra prototypes, and save yourself the
> >> extra check. Not a big deal though.
> >>
> > 
> > I thought about this, but the problem is that strictly speaking, you
> > don't need to consume any LRs to set the underflow, you just need enough
> > in the AP list, and it's theoretically possible that you have nr_lrs+1
> > interrupts in the AP list which have all been migrated away.
> 
> But isn't that a problem we already have, independently of reworking the
> above?
> 

Sort of, but it doesn't really hurt anyone, because we currently always
clear the underflow bit unconditionally, so worst case, you'll take an
additional exit.

After I introduce the conditionals on the sync side, you could loop
forever between KVM/VM.

> > So, it would require something like this including a rework in
> > flush_lr_state to work with the following patch which only calls
> > vgic_fold_lr_state when there are in fact anything live in LRs:
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > index e5cf930..4b1feef 100644
> > --- a/virt/kvm/arm/vgic/vgic.c
> > +++ b/virt/kvm/arm/vgic/vgic.c
> > @@ -601,10 +601,8 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> >  
> >  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> >  
> > -	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> > -		vgic_set_underflow(vcpu);
> > +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr)
> >  		vgic_sort_ap_list(vcpu);
> > -	}
> >  
> >  	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> >  		spin_lock(&irq->irq_lock);
> > @@ -623,8 +621,12 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> >  next:
> >  		spin_unlock(&irq->irq_lock);
> >  
> > -		if (count == kvm_vgic_global_state.nr_lr)
> > +		if (count == kvm_vgic_global_state.nr_lr) {
> > +			if (!list_is_last(&irq->ap_list,
> > +					  &vgic_cpu->ap_list_head))
> > +				vgic_set_underflow(vcpu);
> >  			break;
> > +		}
> >  	}
> >  
> >  	vcpu->arch.vgic_cpu.used_lrs = count;
> > 
> > What do you think?
> 
> I think this deserves a patch of its own. Also, how about renaming
> clear_uie to clear_underflow?
> 
Fair enough, I can add this.

Thanks,
-Christoffer

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

* Re: [PATCH 9/9] KVM: arm/arm64: vgic: Improve sync_hwstate performance
  2017-03-21 13:29     ` Marc Zyngier
@ 2017-03-21 14:13       ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 14:13 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvmarm, linux-arm-kernel, kvm, Andre Przywara, Eric Auger

On Tue, Mar 21, 2017 at 01:29:06PM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > There is no need to call any functions to fold LRs when we don't use any
> > LRs and we don't need to mess with overflow flags, take spinlocks, or
> > prune the AP list if the AP list is empty.
> > 
> > Note: list_empty is a single atomic read (uses READ_ONCE) and can
> > therefore check if a list is empty or not without the need to take the
> > spinlock protecting the list.
> > 
> > Signed-off-by: Christoffer Dall <cdall@linaro.org>
> > ---
> >  virt/kvm/arm/vgic/vgic.c | 13 ++++++++-----
> >  1 file changed, 8 insertions(+), 5 deletions(-)
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > index 093873e..8ecb009 100644
> > --- a/virt/kvm/arm/vgic/vgic.c
> > +++ b/virt/kvm/arm/vgic/vgic.c
> > @@ -639,15 +639,18 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> >  {
> >  	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> >  
> > -	if (unlikely(!vgic_initialized(vcpu->kvm)))
> 
> Could this be folded with the previous patch? It is the same optimisation.
> 

Sure.

> > +	/* An empty ap_list_head implies used_lrs == 0 */
> > +	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
> >  		return;
> >  
> >  	vgic_clear_uie(vcpu);
> > -	vgic_fold_lr_state(vcpu);
> > -	vgic_prune_ap_list(vcpu);
> >  
> > -	/* Make sure we can fast-path in flush_hwstate */
> > -	vgic_cpu->used_lrs = 0;
> > +	if (vgic_cpu->used_lrs) {
> > +		vgic_fold_lr_state(vcpu);
> > +		vgic_cpu->used_lrs = 0;
> 
> This zeroing could also be moved to vgic_fold_lr_state(), though I don't
> feel strongly about it.
> 

Hmm, I'll have a look.

> > +	}
> > +
> > +	vgic_prune_ap_list(vcpu);
> >  }
> >  
> >  /* Flush our emulation state into the GIC hardware before entering the guest. */
> > 
> 
> Otherwise looks good to me.
> 

Thanks,
-Christoffer

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

* [PATCH 9/9] KVM: arm/arm64: vgic: Improve sync_hwstate performance
@ 2017-03-21 14:13       ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2017-03-21 14:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 21, 2017 at 01:29:06PM +0000, Marc Zyngier wrote:
> On 20/03/17 10:58, Christoffer Dall wrote:
> > There is no need to call any functions to fold LRs when we don't use any
> > LRs and we don't need to mess with overflow flags, take spinlocks, or
> > prune the AP list if the AP list is empty.
> > 
> > Note: list_empty is a single atomic read (uses READ_ONCE) and can
> > therefore check if a list is empty or not without the need to take the
> > spinlock protecting the list.
> > 
> > Signed-off-by: Christoffer Dall <cdall@linaro.org>
> > ---
> >  virt/kvm/arm/vgic/vgic.c | 13 ++++++++-----
> >  1 file changed, 8 insertions(+), 5 deletions(-)
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > index 093873e..8ecb009 100644
> > --- a/virt/kvm/arm/vgic/vgic.c
> > +++ b/virt/kvm/arm/vgic/vgic.c
> > @@ -639,15 +639,18 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> >  {
> >  	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> >  
> > -	if (unlikely(!vgic_initialized(vcpu->kvm)))
> 
> Could this be folded with the previous patch? It is the same optimisation.
> 

Sure.

> > +	/* An empty ap_list_head implies used_lrs == 0 */
> > +	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
> >  		return;
> >  
> >  	vgic_clear_uie(vcpu);
> > -	vgic_fold_lr_state(vcpu);
> > -	vgic_prune_ap_list(vcpu);
> >  
> > -	/* Make sure we can fast-path in flush_hwstate */
> > -	vgic_cpu->used_lrs = 0;
> > +	if (vgic_cpu->used_lrs) {
> > +		vgic_fold_lr_state(vcpu);
> > +		vgic_cpu->used_lrs = 0;
> 
> This zeroing could also be moved to vgic_fold_lr_state(), though I don't
> feel strongly about it.
> 

Hmm, I'll have a look.

> > +	}
> > +
> > +	vgic_prune_ap_list(vcpu);
> >  }
> >  
> >  /* Flush our emulation state into the GIC hardware before entering the guest. */
> > 
> 
> Otherwise looks good to me.
> 

Thanks,
-Christoffer

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

end of thread, other threads:[~2017-03-21 14:13 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-20 10:58 [PATCH 0/9] KVM: arm/arm64: vgic: Improvements and optimizations Christoffer Dall
2017-03-20 10:58 ` Christoffer Dall
2017-03-20 10:58 ` [PATCH 1/9] KVM: arm/arm64: vgic: Defer touching GICH_VMCR to vcpu_load/put Christoffer Dall
2017-03-20 10:58   ` Christoffer Dall
2017-03-21 10:29   ` Marc Zyngier
2017-03-21 10:29     ` Marc Zyngier
2017-03-21 11:16     ` Christoffer Dall
2017-03-21 11:16       ` Christoffer Dall
2017-03-20 10:58 ` [PATCH 2/9] KVM: arm/arm64: vgic: Avoid flushing vgic state when there's no pending IRQ Christoffer Dall
2017-03-20 10:58   ` Christoffer Dall
2017-03-21 10:57   ` Marc Zyngier
2017-03-21 10:57     ` Marc Zyngier
2017-03-21 11:17     ` Christoffer Dall
2017-03-21 11:17       ` Christoffer Dall
2017-03-20 10:58 ` [PATCH 3/9] KVM: arm/arm64: vgic: Get rid of live_lrs Christoffer Dall
2017-03-20 10:58   ` Christoffer Dall
2017-03-21 11:06   ` Marc Zyngier
2017-03-21 11:06     ` Marc Zyngier
2017-03-20 10:58 ` [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operation Christoffer Dall
2017-03-20 10:58   ` Christoffer Dall
2017-03-21 11:36   ` Marc Zyngier
2017-03-21 11:36     ` Marc Zyngier
2017-03-21 12:26     ` [PATCH 4/9] KVM: arm/arm64: vgic: Get rid of unnecessary process_maintenance operationjjjj Christoffer Dall
2017-03-21 12:26       ` Christoffer Dall
2017-03-21 13:26       ` Marc Zyngier
2017-03-21 13:26         ` Marc Zyngier
2017-03-21 14:10         ` Christoffer Dall
2017-03-21 14:10           ` Christoffer Dall
2017-03-20 10:58 ` [PATCH 5/9] KVM: arm/arm64: vgic: Get rid of unnecessary save_maint_int_state Christoffer Dall
2017-03-20 10:58   ` Christoffer Dall
2017-03-21 11:44   ` Marc Zyngier
2017-03-21 11:44     ` Marc Zyngier
2017-03-20 10:58 ` [PATCH 6/9] KVM: arm/arm64: vgic: Get rid of MISR and EISR fields Christoffer Dall
2017-03-20 10:58   ` Christoffer Dall
2017-03-21 11:45   ` Marc Zyngier
2017-03-21 11:45     ` Marc Zyngier
2017-03-20 10:58 ` [PATCH 7/9] KVM: arm/arm64: vgic: Implement early VGIC init functionality Christoffer Dall
2017-03-20 10:58   ` Christoffer Dall
2017-03-21 12:05   ` Marc Zyngier
2017-03-21 12:05     ` Marc Zyngier
2017-03-21 12:29     ` Christoffer Dall
2017-03-21 12:29       ` Christoffer Dall
2017-03-21 13:30       ` Marc Zyngier
2017-03-21 13:30         ` Marc Zyngier
2017-03-20 10:58 ` [PATCH 8/9] KVM: arm/arm64: vgic: Don't check vgic_initialized in flush_hwstate Christoffer Dall
2017-03-20 10:58   ` Christoffer Dall
2017-03-21 12:08   ` Marc Zyngier
2017-03-21 12:08     ` Marc Zyngier
2017-03-21 12:30     ` Christoffer Dall
2017-03-21 12:30       ` Christoffer Dall
2017-03-20 10:58 ` [PATCH 9/9] KVM: arm/arm64: vgic: Improve sync_hwstate performance Christoffer Dall
2017-03-20 10:58   ` Christoffer Dall
2017-03-21 13:29   ` Marc Zyngier
2017-03-21 13:29     ` Marc Zyngier
2017-03-21 14:13     ` Christoffer Dall
2017-03-21 14:13       ` Christoffer Dall

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