OSDN Git Service

KVM: PPC: Book3S HV: Move interrupt delivery on guest entry to C code
authorPaul Mackerras <paulus@ozlabs.org>
Mon, 8 Oct 2018 05:30:50 +0000 (16:30 +1100)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 9 Oct 2018 05:04:27 +0000 (16:04 +1100)
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>
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_builtin.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S

index 38d0328..03a60f7 100644 (file)
@@ -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
index 3e3a715..49a686c 100644 (file)
@@ -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;
index fc6bb96..ccfea5b 100644 (file)
@@ -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;
+       }
+}
index 77960e6..6752da1 100644 (file)
@@ -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: