Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d241aac7 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

arm64: KVM: Yield CPU when vcpu executes a WFE



On an (even slightly) oversubscribed system, spinlocks are quickly
becoming a bottleneck, as some vcpus are spinning, waiting for a
lock to be released, while the vcpu holding the lock may not be
running at all.

The solution is to trap blocking WFEs and tell KVM that we're
now spinning. This ensures that other vpus will get a scheduling
boost, allowing the lock to be released more quickly. Also, using
CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT slightly improves the performance
when the VM is severely overcommited.

Acked-by: default avatarChristoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent 4a10c2ac
Loading
Loading
Loading
Loading
+6 −2
Original line number Original line Diff line number Diff line
@@ -63,6 +63,7 @@
 * TAC:		Trap ACTLR
 * TAC:		Trap ACTLR
 * TSC:		Trap SMC
 * TSC:		Trap SMC
 * TSW:		Trap cache operations by set/way
 * TSW:		Trap cache operations by set/way
 * TWE:		Trap WFE
 * TWI:		Trap WFI
 * TWI:		Trap WFI
 * TIDCP:	Trap L2CTLR/L2ECTLR
 * TIDCP:	Trap L2CTLR/L2ECTLR
 * BSU_IS:	Upgrade barriers to the inner shareable domain
 * BSU_IS:	Upgrade barriers to the inner shareable domain
@@ -72,8 +73,9 @@
 * FMO:		Override CPSR.F and enable signaling with VF
 * FMO:		Override CPSR.F and enable signaling with VF
 * SWIO:	Turn set/way invalidates into set/way clean+invalidate
 * SWIO:	Turn set/way invalidates into set/way clean+invalidate
 */
 */
#define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
#define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
			 HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
			 HCR_BSU_IS | HCR_FB | HCR_TAC | \
			 HCR_AMO | HCR_IMO | HCR_FMO | \
			 HCR_SWIO | HCR_TIDCP | HCR_RW)
			 HCR_SWIO | HCR_TIDCP | HCR_RW)
#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)


@@ -242,4 +244,6 @@


#define ESR_EL2_EC_xABT_xFSR_EXTABT	0x10
#define ESR_EL2_EC_xABT_xFSR_EXTABT	0x10


#define ESR_EL2_EC_WFI_ISS_WFE	(1 << 0)

#endif /* __ARM64_KVM_ARM_H__ */
#endif /* __ARM64_KVM_ARM_H__ */
+1 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ config KVM
	select MMU_NOTIFIER
	select MMU_NOTIFIER
	select PREEMPT_NOTIFIERS
	select PREEMPT_NOTIFIERS
	select ANON_INODES
	select ANON_INODES
	select HAVE_KVM_CPU_RELAX_INTERCEPT
	select KVM_MMIO
	select KVM_MMIO
	select KVM_ARM_HOST
	select KVM_ARM_HOST
	select KVM_ARM_VGIC
	select KVM_ARM_VGIC
+13 −5
Original line number Original line Diff line number Diff line
@@ -47,21 +47,29 @@ static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
}
}


/**
/**
 * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest
 * kvm_handle_wfx - handle a wait-for-interrupts or wait-for-event
 *		    instruction executed by a guest
 *
 * @vcpu:	the vcpu pointer
 * @vcpu:	the vcpu pointer
 *
 *
 * Simply call kvm_vcpu_block(), which will halt execution of
 * WFE: Yield the CPU and come back to this vcpu when the scheduler
 * decides to.
 * WFI: Simply call kvm_vcpu_block(), which will halt execution of
 * world-switches and schedule other host processes until there is an
 * world-switches and schedule other host processes until there is an
 * incoming IRQ or FIQ to the VM.
 * incoming IRQ or FIQ to the VM.
 */
 */
static int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
{
	if (kvm_vcpu_get_hsr(vcpu) & ESR_EL2_EC_WFI_ISS_WFE)
		kvm_vcpu_on_spin(vcpu);
	else
		kvm_vcpu_block(vcpu);
		kvm_vcpu_block(vcpu);

	return 1;
	return 1;
}
}


static exit_handle_fn arm_exit_handlers[] = {
static exit_handle_fn arm_exit_handlers[] = {
	[ESR_EL2_EC_WFI]	= kvm_handle_wfi,
	[ESR_EL2_EC_WFI]	= kvm_handle_wfx,
	[ESR_EL2_EC_CP15_32]	= kvm_handle_cp15_32,
	[ESR_EL2_EC_CP15_32]	= kvm_handle_cp15_32,
	[ESR_EL2_EC_CP15_64]	= kvm_handle_cp15_64,
	[ESR_EL2_EC_CP15_64]	= kvm_handle_cp15_64,
	[ESR_EL2_EC_CP14_MR]	= kvm_handle_cp14_access,
	[ESR_EL2_EC_CP14_MR]	= kvm_handle_cp14_access,