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: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Paul Mackerras <paulus@ozlabs.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
966eba9316
commit
f7035ce9f1
@ -650,6 +650,7 @@ int kvmppc_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server,
|
|||||||
unsigned long mfrr);
|
unsigned long mfrr);
|
||||||
int kvmppc_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr);
|
int kvmppc_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr);
|
||||||
int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr);
|
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
|
* Host-side operations we want to set up while running in real
|
||||||
|
@ -730,8 +730,7 @@ static bool kvmppc_doorbell_pending(struct kvm_vcpu *vcpu)
|
|||||||
/*
|
/*
|
||||||
* Ensure that the read of vcore->dpdes comes after the read
|
* Ensure that the read of vcore->dpdes comes after the read
|
||||||
* of vcpu->doorbell_request. This barrier matches the
|
* of vcpu->doorbell_request. This barrier matches the
|
||||||
* lwsync in book3s_hv_rmhandlers.S just before the
|
* smb_wmb() in kvmppc_guest_entry_inject().
|
||||||
* fast_guest_return label.
|
|
||||||
*/
|
*/
|
||||||
smp_rmb();
|
smp_rmb();
|
||||||
vc = vcpu->arch.vcore;
|
vc = vcpu->arch.vcore;
|
||||||
|
@ -729,3 +729,51 @@ void kvmhv_p9_restore_lpcr(struct kvm_split_mode *sip)
|
|||||||
smp_mb();
|
smp_mb();
|
||||||
local_paca->kvm_hstate.kvm_split_mode = NULL;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1101,13 +1101,20 @@ no_xive:
|
|||||||
#endif /* CONFIG_KVM_XICS */
|
#endif /* CONFIG_KVM_XICS */
|
||||||
|
|
||||||
deliver_guest_interrupt:
|
deliver_guest_interrupt:
|
||||||
ld r6, VCPU_CTR(r4)
|
|
||||||
ld r7, VCPU_XER(r4)
|
|
||||||
|
|
||||||
mtctr r6
|
|
||||||
mtxer r7
|
|
||||||
|
|
||||||
kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */
|
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 r10, VCPU_PC(r4)
|
||||||
ld r11, VCPU_MSR(r4)
|
ld r11, VCPU_MSR(r4)
|
||||||
ld r6, VCPU_SRR0(r4)
|
ld r6, VCPU_SRR0(r4)
|
||||||
@ -1120,53 +1127,10 @@ kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */
|
|||||||
rotldi r11, r11, 1 + MSR_HV_LG
|
rotldi r11, r11, 1 + MSR_HV_LG
|
||||||
ori r11, r11, MSR_ME
|
ori r11, r11, MSR_ME
|
||||||
|
|
||||||
/* Check if we can deliver an external or decrementer interrupt now */
|
ld r6, VCPU_CTR(r4)
|
||||||
ld r0, VCPU_PENDING_EXC(r4)
|
ld r7, VCPU_XER(r4)
|
||||||
rldicl r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL, 63
|
mtctr r6
|
||||||
cmpdi cr1, r0, 0
|
mtxer r7
|
||||||
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)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Required state:
|
* Required state:
|
||||||
|
Loading…
Reference in New Issue
Block a user