]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kvm/book3s_hv_rmhandlers.S
Merge tag 'char-misc-4.13-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregk...
[karo-tx-linux.git] / arch / powerpc / kvm / book3s_hv_rmhandlers.S
index cb44065e29463f99d6c44bf129ca01e82695a8ff..c52184a8efdf025c1efffc6dd7310e9374dca630 100644 (file)
@@ -1443,12 +1443,14 @@ mc_cont:
        ori     r6,r6,1
        mtspr   SPRN_CTRLT,r6
 4:
-       /* Read the guest SLB and save it away */
+       /* Check if we are running hash or radix and store it in cr2 */
        ld      r5, VCPU_KVM(r9)
        lbz     r0, KVM_RADIX(r5)
-       cmpwi   r0, 0
+       cmpwi   cr2,r0,0
+
+       /* Read the guest SLB and save it away */
        li      r5, 0
-       bne     3f                      /* for radix, save 0 entries */
+       bne     cr2, 3f                 /* for radix, save 0 entries */
        lwz     r0,VCPU_SLB_NR(r9)      /* number of entries in SLB */
        mtctr   r0
        li      r6,0
@@ -1712,11 +1714,6 @@ BEGIN_FTR_SECTION_NESTED(96)
 END_FTR_SECTION_NESTED(CPU_FTR_ARCH_300, 0, 96)
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 22:
-       /* Clear out SLB */
-       li      r5,0
-       slbmte  r5,r5
-       slbia
-       ptesync
 
        /* Restore host values of some registers */
 BEGIN_FTR_SECTION
@@ -1737,10 +1734,56 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_PID, r7
        mtspr   SPRN_IAMR, r8
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
+
+#ifdef CONFIG_PPC_RADIX_MMU
+       /*
+        * Are we running hash or radix ?
+        */
+       beq     cr2,3f
+
+       /* Radix: Handle the case where the guest used an illegal PID */
+       LOAD_REG_ADDR(r4, mmu_base_pid)
+       lwz     r3, VCPU_GUEST_PID(r9)
+       lwz     r5, 0(r4)
+       cmpw    cr0,r3,r5
+       blt     2f
+
+       /*
+        * Illegal PID, the HW might have prefetched and cached in the TLB
+        * some translations for the  LPID 0 / guest PID combination which
+        * Linux doesn't know about, so we need to flush that PID out of
+        * the TLB. First we need to set LPIDR to 0 so tlbiel applies to
+        * the right context.
+       */
+       li      r0,0
+       mtspr   SPRN_LPID,r0
+       isync
+
+       /* Then do a congruence class local flush */
+       ld      r6,VCPU_KVM(r9)
+       lwz     r0,KVM_TLB_SETS(r6)
+       mtctr   r0
+       li      r7,0x400                /* IS field = 0b01 */
+       ptesync
+       sldi    r0,r3,32                /* RS has PID */
+1:     PPC_TLBIEL(7,0,2,1,1)           /* RIC=2, PRS=1, R=1 */
+       addi    r7,r7,0x1000
+       bdnz    1b
+       ptesync
+
+2:     /* Flush the ERAT on radix P9 DD1 guest exit */
 BEGIN_FTR_SECTION
        PPC_INVALIDATE_ERAT
 END_FTR_SECTION_IFSET(CPU_FTR_POWER9_DD1)
+       b       4f
+#endif /* CONFIG_PPC_RADIX_MMU */
 
+       /* Hash: clear out SLB */
+3:     li      r5,0
+       slbmte  r5,r5
+       slbia
+       ptesync
+4:
        /*
         * POWER7/POWER8 guest -> host partition switch code.
         * We don't have to lock against tlbies but we do