]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kvm/book3s_hv_rmhandlers.S
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[karo-tx-linux.git] / arch / powerpc / kvm / book3s_hv_rmhandlers.S
index 9338a818e05cf8a7285471bca75cad2c8c2a7a46..7c6477d1840aab488cbec7ffe813696fd63f861f 100644 (file)
@@ -148,6 +148,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        addi    r1, r1, 112
        ld      r7, HSTATE_HOST_MSR(r13)
 
+       /*
+        * If we came back from the guest via a relocation-on interrupt,
+        * we will be in virtual mode at this point, which makes it a
+        * little easier to get back to the caller.
+        */
+       mfmsr   r0
+       andi.   r0, r0, MSR_IR          /* in real mode? */
+       bne     .Lvirt_return
+
        cmpwi   cr1, r12, BOOK3S_INTERRUPT_MACHINE_CHECK
        cmpwi   r12, BOOK3S_INTERRUPT_EXTERNAL
        beq     11f
@@ -181,6 +190,26 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        mtspr SPRN_HSRR1, r7
        ba    0xe80
 
+       /* Virtual-mode return - can't get here for HMI or machine check */
+.Lvirt_return:
+       cmpwi   r12, BOOK3S_INTERRUPT_EXTERNAL
+       beq     16f
+       cmpwi   r12, BOOK3S_INTERRUPT_H_DOORBELL
+       beq     17f
+       andi.   r0, r7, MSR_EE          /* were interrupts hard-enabled? */
+       beq     18f
+       mtmsrd  r7, 1                   /* if so then re-enable them */
+18:    mtlr    r8
+       blr
+
+16:    mtspr   SPRN_HSRR0, r8          /* jump to reloc-on external vector */
+       mtspr   SPRN_HSRR1, r7
+       b       exc_virt_0x4500_hardware_interrupt
+
+17:    mtspr   SPRN_HSRR0, r8
+       mtspr   SPRN_HSRR1, r7
+       b       exc_virt_0x4e80_h_doorbell
+
 kvmppc_primary_no_guest:
        /* We handle this much like a ceded vcpu */
        /* put the HDEC into the DEC, since HDEC interrupts don't wake us */
@@ -518,6 +547,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 /* Stack frame offsets */
 #define STACK_SLOT_TID         (112-16)
 #define STACK_SLOT_PSSCR       (112-24)
+#define STACK_SLOT_PID         (112-32)
 
 .global kvmppc_hv_entry
 kvmppc_hv_entry:
@@ -530,6 +560,7 @@ kvmppc_hv_entry:
         * R1 = host R1
         * R2 = TOC
         * all other volatile GPRS = free
+        * Does not preserve non-volatile GPRs or CR fields
         */
        mflr    r0
        std     r0, PPC_LR_STKOFF(r1)
@@ -549,32 +580,38 @@ kvmppc_hv_entry:
        bl      kvmhv_start_timing
 1:
 #endif
-       /* Clear out SLB */
+
+       /* Use cr7 as an indication of radix mode */
+       ld      r5, HSTATE_KVM_VCORE(r13)
+       ld      r9, VCORE_KVM(r5)       /* pointer to struct kvm */
+       lbz     r0, KVM_RADIX(r9)
+       cmpwi   cr7, r0, 0
+
+       /* Clear out SLB if hash */
+       bne     cr7, 2f
        li      r6,0
        slbmte  r6,r6
        slbia
        ptesync
-
+2:
        /*
         * POWER7/POWER8 host -> guest partition switch code.
         * We don't have to lock against concurrent tlbies,
         * but we do have to coordinate across hardware threads.
         */
        /* Set bit in entry map iff exit map is zero. */
-       ld      r5, HSTATE_KVM_VCORE(r13)
        li      r7, 1
        lbz     r6, HSTATE_PTID(r13)
        sld     r7, r7, r6
-       addi    r9, r5, VCORE_ENTRY_EXIT
-21:    lwarx   r3, 0, r9
+       addi    r8, r5, VCORE_ENTRY_EXIT
+21:    lwarx   r3, 0, r8
        cmpwi   r3, 0x100               /* any threads starting to exit? */
        bge     secondary_too_late      /* if so we're too late to the party */
        or      r3, r3, r7
-       stwcx.  r3, 0, r9
+       stwcx.  r3, 0, r8
        bne     21b
 
        /* Primary thread switches to guest partition. */
-       ld      r9,VCORE_KVM(r5)        /* pointer to struct kvm */
        cmpwi   r6,0
        bne     10f
        lwz     r7,KVM_LPID(r9)
@@ -590,30 +627,44 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
 
        /* See if we need to flush the TLB */
        lhz     r6,PACAPACAINDEX(r13)   /* test_bit(cpu, need_tlb_flush) */
+BEGIN_FTR_SECTION
+       /*
+        * On POWER9, individual threads can come in here, but the
+        * TLB is shared between the 4 threads in a core, hence
+        * invalidating on one thread invalidates for all.
+        * Thus we make all 4 threads use the same bit here.
+        */
+       clrrdi  r6,r6,2
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        clrldi  r7,r6,64-6              /* extract bit number (6 bits) */
        srdi    r6,r6,6                 /* doubleword number */
        sldi    r6,r6,3                 /* address offset */
        add     r6,r6,r9
        addi    r6,r6,KVM_NEED_FLUSH    /* dword in kvm->arch.need_tlb_flush */
-       li      r0,1
-       sld     r0,r0,r7
+       li      r8,1
+       sld     r8,r8,r7
        ld      r7,0(r6)
-       and.    r7,r7,r0
+       and.    r7,r7,r8
        beq     22f
-23:    ldarx   r7,0,r6                 /* if set, clear the bit */
-       andc    r7,r7,r0
-       stdcx.  r7,0,r6
-       bne     23b
        /* Flush the TLB of any entries for this LPID */
-       lwz     r6,KVM_TLB_SETS(r9)
-       li      r0,0                    /* RS for P9 version of tlbiel */
-       mtctr   r6
+       lwz     r0,KVM_TLB_SETS(r9)
+       mtctr   r0
        li      r7,0x800                /* IS field = 0b10 */
        ptesync
-28:    tlbiel  r7
+       li      r0,0                    /* RS for P9 version of tlbiel */
+       bne     cr7, 29f
+28:    tlbiel  r7                      /* On P9, rs=0, RIC=0, PRS=0, R=0 */
        addi    r7,r7,0x1000
        bdnz    28b
-       ptesync
+       b       30f
+29:    PPC_TLBIEL(7,0,2,1,1)           /* for radix, RIC=2, PRS=1, R=1 */
+       addi    r7,r7,0x1000
+       bdnz    29b
+30:    ptesync
+23:    ldarx   r7,0,r6                 /* clear the bit after TLB flushed */
+       andc    r7,r7,r8
+       stdcx.  r7,0,r6
+       bne     23b
 
        /* Add timebase offset onto timebase */
 22:    ld      r8,VCORE_TB_OFFSET(r5)
@@ -658,7 +709,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        beq     kvmppc_primary_no_guest
 kvmppc_got_guest:
 
-       /* Load up guest SLB entries */
+       /* Load up guest SLB entries (N.B. slb_max will be 0 for radix) */
        lwz     r5,VCPU_SLB_MAX(r4)
        cmpwi   r5,0
        beq     9f
@@ -696,8 +747,10 @@ kvmppc_got_guest:
 BEGIN_FTR_SECTION
        mfspr   r5, SPRN_TIDR
        mfspr   r6, SPRN_PSSCR
+       mfspr   r7, SPRN_PID
        std     r5, STACK_SLOT_TID(r1)
        std     r6, STACK_SLOT_PSSCR(r1)
+       std     r7, STACK_SLOT_PID(r1)
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
 
 BEGIN_FTR_SECTION
@@ -823,6 +876,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
        mtspr   SPRN_BESCR, r6
        mtspr   SPRN_PID, r7
        mtspr   SPRN_WORT, r8
+BEGIN_FTR_SECTION
+       PPC_INVALIDATE_ERAT
+END_FTR_SECTION_IFSET(CPU_FTR_POWER9_DD1)
 BEGIN_FTR_SECTION
        /* POWER8-only registers */
        ld      r5, VCPU_TCSCR(r4)
@@ -1057,13 +1113,13 @@ hdec_soon:
 kvmppc_interrupt_hv:
        /*
         * Register contents:
-        * R12          = interrupt vector
+        * R12          = (guest CR << 32) | interrupt vector
         * R13          = PACA
-        * guest CR, R12 saved in shadow VCPU SCRATCH1/0
+        * guest R12 saved in shadow VCPU SCRATCH0
+        * guest CTR saved in shadow VCPU SCRATCH1 if RELOCATABLE
         * guest R13 saved in SPRN_SCRATCH0
         */
        std     r9, HSTATE_SCRATCH2(r13)
-
        lbz     r9, HSTATE_IN_GUEST(r13)
        cmpwi   r9, KVM_GUEST_MODE_HOST_HV
        beq     kvmppc_bad_host_intr
@@ -1094,8 +1150,9 @@ kvmppc_interrupt_hv:
        std     r10, VCPU_GPR(R10)(r9)
        std     r11, VCPU_GPR(R11)(r9)
        ld      r3, HSTATE_SCRATCH0(r13)
-       lwz     r4, HSTATE_SCRATCH1(r13)
        std     r3, VCPU_GPR(R12)(r9)
+       /* CR is in the high half of r12 */
+       srdi    r4, r12, 32
        stw     r4, VCPU_CR(r9)
 BEGIN_FTR_SECTION
        ld      r3, HSTATE_CFAR(r13)
@@ -1114,6 +1171,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        mfspr   r11, SPRN_SRR1
        std     r10, VCPU_SRR0(r9)
        std     r11, VCPU_SRR1(r9)
+       /* trap is in the low half of r12, clear CR from the high half */
+       clrldi  r12, r12, 32
        andi.   r0, r12, 2              /* need to read HSRR0/1? */
        beq     1f
        mfspr   r10, SPRN_HSRR0
@@ -1149,7 +1208,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
 11:    stw     r3,VCPU_HEIR(r9)
 
        /* these are volatile across C function calls */
+#ifdef CONFIG_RELOCATABLE
+       ld      r3, HSTATE_SCRATCH1(r13)
+       mtctr   r3
+#else
        mfctr   r3
+#endif
        mfxer   r4
        std     r3, VCPU_CTR(r9)
        std     r4, VCPU_XER(r9)
@@ -1285,11 +1349,15 @@ mc_cont:
        mtspr   SPRN_CTRLT,r6
 4:
        /* Read the guest SLB and save it away */
+       ld      r5, VCPU_KVM(r9)
+       lbz     r0, KVM_RADIX(r5)
+       cmpwi   r0, 0
+       li      r5, 0
+       bne     3f                      /* for radix, save 0 entries */
        lwz     r0,VCPU_SLB_NR(r9)      /* number of entries in SLB */
        mtctr   r0
        li      r6,0
        addi    r7,r9,VCPU_SLB
-       li      r5,0
 1:     slbmfee r8,r6
        andis.  r0,r8,SLB_ESID_V@h
        beq     2f
@@ -1301,7 +1369,7 @@ mc_cont:
        addi    r5,r5,1
 2:     addi    r6,r6,1
        bdnz    1b
-       stw     r5,VCPU_SLB_MAX(r9)
+3:     stw     r5,VCPU_SLB_MAX(r9)
 
        /*
         * Save the guest PURR/SPURR
@@ -1550,9 +1618,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 BEGIN_FTR_SECTION
        ld      r5, STACK_SLOT_TID(r1)
        ld      r6, STACK_SLOT_PSSCR(r1)
+       ld      r7, STACK_SLOT_PID(r1)
        mtspr   SPRN_TIDR, r5
        mtspr   SPRN_PSSCR, r6
+       mtspr   SPRN_PID, r7
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
+BEGIN_FTR_SECTION
+       PPC_INVALIDATE_ERAT
+END_FTR_SECTION_IFSET(CPU_FTR_POWER9_DD1)
 
        /*
         * POWER7/POWER8 guest -> host partition switch code.
@@ -1663,6 +1736,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        isync
 
        /* load host SLB entries */
+BEGIN_MMU_FTR_SECTION
+       b       0f
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
        ld      r8,PACA_SLBSHADOWPTR(r13)
 
        .rept   SLB_NUM_BOLTED
@@ -1675,7 +1751,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        slbmte  r6,r5
 1:     addi    r8,r8,16
        .endr
-
+0:
 #ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
        /* Finish timing, if we have a vcpu */
        ld      r4, HSTATE_KVM_VCPU(r13)
@@ -1702,13 +1778,21 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
  * reflect the HDSI to the guest as a DSI.
  */
 kvmppc_hdsi:
+       ld      r3, VCPU_KVM(r9)
+       lbz     r0, KVM_RADIX(r3)
+       cmpwi   r0, 0
        mfspr   r4, SPRN_HDAR
        mfspr   r6, SPRN_HDSISR
+       bne     .Lradix_hdsi            /* on radix, just save DAR/DSISR/ASDR */
        /* HPTE not found fault or protection fault? */
        andis.  r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h
        beq     1f                      /* if not, send it to the guest */
        andi.   r0, r11, MSR_DR         /* data relocation enabled? */
        beq     3f
+BEGIN_FTR_SECTION
+       mfspr   r5, SPRN_ASDR           /* on POWER9, use ASDR to get VSID */
+       b       4f
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        clrrdi  r0, r4, 28
        PPC_SLBFEE_DOT(R5, R0)          /* if so, look up SLB */
        li      r0, BOOK3S_INTERRUPT_DATA_SEGMENT
@@ -1776,15 +1860,31 @@ fast_interrupt_c_return:
        stb     r0, HSTATE_IN_GUEST(r13)
        b       guest_exit_cont
 
+.Lradix_hdsi:
+       std     r4, VCPU_FAULT_DAR(r9)
+       stw     r6, VCPU_FAULT_DSISR(r9)
+.Lradix_hisi:
+       mfspr   r5, SPRN_ASDR
+       std     r5, VCPU_FAULT_GPA(r9)
+       b       guest_exit_cont
+
 /*
  * Similarly for an HISI, reflect it to the guest as an ISI unless
  * it is an HPTE not found fault for a page that we have paged out.
  */
 kvmppc_hisi:
+       ld      r3, VCPU_KVM(r9)
+       lbz     r0, KVM_RADIX(r3)
+       cmpwi   r0, 0
+       bne     .Lradix_hisi            /* for radix, just save ASDR */
        andis.  r0, r11, SRR1_ISI_NOPT@h
        beq     1f
        andi.   r0, r11, MSR_IR         /* instruction relocation enabled? */
        beq     3f
+BEGIN_FTR_SECTION
+       mfspr   r5, SPRN_ASDR           /* on POWER9, use ASDR to get VSID */
+       b       4f
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        clrrdi  r0, r10, 28
        PPC_SLBFEE_DOT(R5, R0)          /* if so, look up SLB */
        li      r0, BOOK3S_INTERRUPT_INST_SEGMENT