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

Commit f7035ce9 authored by Paul Mackerras's avatar Paul Mackerras Committed by Michael Ellerman
Browse files

KVM: PPC: Book3S HV: Move interrupt delivery on guest entry to C code



This is based on a patch by Suraj Jitindar Singh.

This moves the code in book3s_hv_rmhandlers.S that generates an
external, decrementer or privileged doorbell interrupt just before
entering the guest to C code in book3s_hv_builtin.c.  This is to
make future maintenance and modification easier.  The algorithm
expressed in the C code is almost identical to the previous
algorithm.

Reviewed-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Signed-off-by: default avatarPaul Mackerras <paulus@ozlabs.org>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 966eba93
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -650,6 +650,7 @@ int kvmppc_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server,
                    unsigned long mfrr);
int kvmppc_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr);
int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr);
void kvmppc_guest_entry_inject_int(struct kvm_vcpu *vcpu);

/*
 * Host-side operations we want to set up while running in real
+1 −2
Original line number Diff line number Diff line
@@ -730,8 +730,7 @@ static bool kvmppc_doorbell_pending(struct kvm_vcpu *vcpu)
	/*
	 * Ensure that the read of vcore->dpdes comes after the read
	 * of vcpu->doorbell_request.  This barrier matches the
	 * lwsync in book3s_hv_rmhandlers.S just before the
	 * fast_guest_return label.
	 * smb_wmb() in kvmppc_guest_entry_inject().
	 */
	smp_rmb();
	vc = vcpu->arch.vcore;
+48 −0
Original line number Diff line number Diff line
@@ -729,3 +729,51 @@ void kvmhv_p9_restore_lpcr(struct kvm_split_mode *sip)
	smp_mb();
	local_paca->kvm_hstate.kvm_split_mode = NULL;
}

/*
 * Is there a PRIV_DOORBELL pending for the guest (on POWER9)?
 * Can we inject a Decrementer or a External interrupt?
 */
void kvmppc_guest_entry_inject_int(struct kvm_vcpu *vcpu)
{
	int ext;
	unsigned long vec = 0;
	unsigned long lpcr;

	/* Insert EXTERNAL bit into LPCR at the MER bit position */
	ext = (vcpu->arch.pending_exceptions >> BOOK3S_IRQPRIO_EXTERNAL) & 1;
	lpcr = mfspr(SPRN_LPCR);
	lpcr |= ext << LPCR_MER_SH;
	mtspr(SPRN_LPCR, lpcr);
	isync();

	if (vcpu->arch.shregs.msr & MSR_EE) {
		if (ext) {
			vec = BOOK3S_INTERRUPT_EXTERNAL;
		} else {
			long int dec = mfspr(SPRN_DEC);
			if (!(lpcr & LPCR_LD))
				dec = (int) dec;
			if (dec < 0)
				vec = BOOK3S_INTERRUPT_DECREMENTER;
		}
	}
	if (vec) {
		unsigned long msr, old_msr = vcpu->arch.shregs.msr;

		kvmppc_set_srr0(vcpu, kvmppc_get_pc(vcpu));
		kvmppc_set_srr1(vcpu, old_msr);
		kvmppc_set_pc(vcpu, vec);
		msr = vcpu->arch.intr_msr;
		if (MSR_TM_ACTIVE(old_msr))
			msr |= MSR_TS_S;
		vcpu->arch.shregs.msr = msr;
	}

	if (vcpu->arch.doorbell_request) {
		mtspr(SPRN_DPDES, 1);
		vcpu->arch.vcore->dpdes = 1;
		smp_wmb();
		vcpu->arch.doorbell_request = 0;
	}
}
+17 −53
Original line number Diff line number Diff line
@@ -1101,13 +1101,20 @@ no_xive:
#endif /* CONFIG_KVM_XICS */

deliver_guest_interrupt:
	ld	r6, VCPU_CTR(r4)
	ld	r7, VCPU_XER(r4)

	mtctr	r6
	mtxer	r7

kvmppc_cede_reentry:		/* r4 = vcpu, r13 = paca */
	/* Check if we can deliver an external or decrementer interrupt now */
	ld	r0, VCPU_PENDING_EXC(r4)
BEGIN_FTR_SECTION
	/* On POWER9, also check for emulated doorbell interrupt */
	lbz	r3, VCPU_DBELL_REQ(r4)
	or	r0, r0, r3
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
	cmpdi	r0, 0
	beq	71f
	mr	r3, r4
	bl	kvmppc_guest_entry_inject_int
	ld	r4, HSTATE_KVM_VCPU(r13)
71:
	ld	r10, VCPU_PC(r4)
	ld	r11, VCPU_MSR(r4)
	ld	r6, VCPU_SRR0(r4)
@@ -1120,53 +1127,10 @@ kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */
	rotldi	r11, r11, 1 + MSR_HV_LG
	ori	r11, r11, MSR_ME

	/* Check if we can deliver an external or decrementer interrupt now */
	ld	r0, VCPU_PENDING_EXC(r4)
	rldicl	r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL, 63
	cmpdi	cr1, r0, 0
	andi.	r8, r11, MSR_EE
	mfspr	r8, SPRN_LPCR
	/* Insert EXTERNAL bit into LPCR at the MER bit position */
	rldimi	r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH
	mtspr	SPRN_LPCR, r8
	isync
	beq	5f
	li	r0, BOOK3S_INTERRUPT_EXTERNAL
	bne	cr1, 12f
	mfspr	r0, SPRN_DEC
BEGIN_FTR_SECTION
	/* On POWER9 check whether the guest has large decrementer enabled */
	andis.	r8, r8, LPCR_LD@h
	bne	15f
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
	extsw	r0, r0
15:	cmpdi	r0, 0
	li	r0, BOOK3S_INTERRUPT_DECREMENTER
	bge	5f

12:	mtspr	SPRN_SRR0, r10
	mr	r10,r0
	mtspr	SPRN_SRR1, r11
	mr	r9, r4
	bl	kvmppc_msr_interrupt
5:
BEGIN_FTR_SECTION
	b	fast_guest_return
END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
	/* On POWER9, check for pending doorbell requests */
	lbz	r0, VCPU_DBELL_REQ(r4)
	cmpwi	r0, 0
	beq	fast_guest_return
	ld	r5, HSTATE_KVM_VCORE(r13)
	/* Set DPDES register so the CPU will take a doorbell interrupt */
	li	r0, 1
	mtspr	SPRN_DPDES, r0
	std	r0, VCORE_DPDES(r5)
	/* Make sure other cpus see vcore->dpdes set before dbell req clear */
	lwsync
	/* Clear the pending doorbell request */
	li	r0, 0
	stb	r0, VCPU_DBELL_REQ(r4)
	ld	r6, VCPU_CTR(r4)
	ld	r7, VCPU_XER(r4)
	mtctr	r6
	mtxer	r7

/*
 * Required state: