Message ID | 1537524123-9578-4-git-send-email-paulus@ozlabs.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | KVM: PPC: Book3S HV: Nested HV virtualization | expand |
On Fri, Sep 21, 2018 at 08:01:34PM +1000, Paul Mackerras wrote: > 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. > > Signed-off-by: Paul Mackerras <paulus@ozlabs.org> Reviewed-by: David Gibson <david@gibson.dropbear.id.au> > --- > arch/powerpc/include/asm/kvm_ppc.h | 1 + > arch/powerpc/kvm/book3s_hv.c | 3 +- > arch/powerpc/kvm/book3s_hv_builtin.c | 48 ++++++++++++++++++++++ > arch/powerpc/kvm/book3s_hv_rmhandlers.S | 70 ++++++++------------------------- > 4 files changed, 67 insertions(+), 55 deletions(-) > > diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h > index e991821..83d61b8 100644 > --- a/arch/powerpc/include/asm/kvm_ppc.h > +++ b/arch/powerpc/include/asm/kvm_ppc.h > @@ -652,6 +652,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 > diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c > index 3e3a715..49a686c 100644 > --- a/arch/powerpc/kvm/book3s_hv.c > +++ b/arch/powerpc/kvm/book3s_hv.c > @@ -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; > diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c > index fc6bb96..ccfea5b 100644 > --- a/arch/powerpc/kvm/book3s_hv_builtin.c > +++ b/arch/powerpc/kvm/book3s_hv_builtin.c > @@ -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; > + } > +} > diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S > index 77960e6..6752da1 100644 > --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S > +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S > @@ -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:
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index e991821..83d61b8 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -652,6 +652,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 diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 3e3a715..49a686c 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -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; diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index fc6bb96..ccfea5b 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c @@ -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; + } +} diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 77960e6..6752da1 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -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:
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. Signed-off-by: Paul Mackerras <paulus@ozlabs.org> --- arch/powerpc/include/asm/kvm_ppc.h | 1 + arch/powerpc/kvm/book3s_hv.c | 3 +- arch/powerpc/kvm/book3s_hv_builtin.c | 48 ++++++++++++++++++++++ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 70 ++++++++------------------------- 4 files changed, 67 insertions(+), 55 deletions(-)