]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kernel/idle_book3s.S
powerpc/64s/idle: Predict HMI wakeup as unlikely
[karo-tx-linux.git] / arch / powerpc / kernel / idle_book3s.S
index 07d4e0ad60db5b1a1f2cd5da08763a3acea7ea3b..1ea14b96f1261c723fd0aa6674f0223c333459af 100644 (file)
@@ -31,6 +31,7 @@
  * registers for winkle support.
  */
 #define _SDR1  GPR3
+#define _PTCR  GPR3
 #define _RPR   GPR4
 #define _SPURR GPR5
 #define _PURR  GPR6
@@ -39,7 +40,7 @@
 #define _AMOR  GPR9
 #define _WORT  GPR10
 #define _WORC  GPR11
-#define _PTCR  GPR12
+#define _LPCR  GPR12
 
 #define PSSCR_EC_ESL_MASK_SHIFTED          (PSSCR_EC | PSSCR_ESL) >> 16
 
@@ -55,12 +56,14 @@ save_sprs_to_stack:
         * here since any thread in the core might wake up first
         */
 BEGIN_FTR_SECTION
-       mfspr   r3,SPRN_PTCR
-       std     r3,_PTCR(r1)
        /*
         * Note - SDR1 is dropped in Power ISA v3. Hence not restoring
         * SDR1 here
         */
+       mfspr   r3,SPRN_PTCR
+       std     r3,_PTCR(r1)
+       mfspr   r3,SPRN_LPCR
+       std     r3,_LPCR(r1)
 FTR_SECTION_ELSE
        mfspr   r3,SPRN_SDR1
        std     r3,_SDR1(r1)
@@ -106,13 +109,9 @@ core_idle_lock_held:
 /*
  * Pass requested state in r3:
  *     r3 - PNV_THREAD_NAP/SLEEP/WINKLE in POWER8
- *        - Requested STOP state in POWER9
- *
- * To check IRQ_HAPPENED in r4
- *     0 - don't check
- *     1 - check
+ *        - Requested PSSCR value in POWER9
  *
- * Address to 'rfid' to in r5
+ * Address of idle handler to branch to in realmode in r4
  */
 pnv_powersave_common:
        /* Use r3 to pass state nap/sleep/winkle */
@@ -122,37 +121,14 @@ pnv_powersave_common:
         * need to save PC, some CR bits and the NV GPRs,
         * but for now an interrupt frame will do.
         */
+       mtctr   r4
+
        mflr    r0
        std     r0,16(r1)
        stdu    r1,-INT_FRAME_SIZE(r1)
        std     r0,_LINK(r1)
        std     r0,_NIP(r1)
 
-       /* Hard disable interrupts */
-       mfmsr   r9
-       rldicl  r9,r9,48,1
-       rotldi  r9,r9,16
-       mtmsrd  r9,1                    /* hard-disable interrupts */
-
-       /* Check if something happened while soft-disabled */
-       lbz     r0,PACAIRQHAPPENED(r13)
-       andi.   r0,r0,~PACA_IRQ_HARD_DIS@l
-       beq     1f
-       cmpwi   cr0,r4,0
-       beq     1f
-       addi    r1,r1,INT_FRAME_SIZE
-       ld      r0,16(r1)
-       li      r3,0                    /* Return 0 (no nap) */
-       mtlr    r0
-       blr
-
-1:     /* We mark irqs hard disabled as this is the state we'll
-        * be in when returning and we need to tell arch_local_irq_restore()
-        * about it
-        */
-       li      r0,PACA_IRQ_HARD_DIS
-       stb     r0,PACAIRQHAPPENED(r13)
-
        /* We haven't lost state ... yet */
        li      r0,0
        stb     r0,PACA_NAPSTATELOST(r13)
@@ -160,9 +136,8 @@ pnv_powersave_common:
        /* Continue saving state */
        SAVE_GPR(2, r1)
        SAVE_NVGPRS(r1)
-       mfcr    r4
-       std     r4,_CCR(r1)
-       std     r9,_MSR(r1)
+       mfcr    r5
+       std     r5,_CCR(r1)
        std     r1,PACAR1(r13)
 
        /*
@@ -172,12 +147,8 @@ pnv_powersave_common:
         * the MMU context to the guest.
         */
        LOAD_REG_IMMEDIATE(r7, MSR_IDLE)
-       li      r6, MSR_RI
-       andc    r6, r9, r6
-       mtmsrd  r6, 1           /* clear RI before setting SRR0/1 */
-       mtspr   SPRN_SRR0, r5
-       mtspr   SPRN_SRR1, r7
-       rfid
+       mtmsrd  r7,0
+       bctr
 
        .globl pnv_enter_arch207_idle_mode
 pnv_enter_arch207_idle_mode:
@@ -319,45 +290,23 @@ lwarx_loop_stop:
 
        IDLE_STATE_ENTER_SEQ_NORET(PPC_STOP)
 
-_GLOBAL(power7_idle)
+/*
+ * Entered with MSR[EE]=0 and no soft-masked interrupts pending.
+ * r3 contains desired idle state (PNV_THREAD_NAP/SLEEP/WINKLE).
+ */
+_GLOBAL(power7_idle_insn)
        /* Now check if user or arch enabled NAP mode */
-       LOAD_REG_ADDRBASE(r3,powersave_nap)
-       lwz     r4,ADDROFF(powersave_nap)(r3)
-       cmpwi   0,r4,0
-       beqlr
-       li      r3, 1
-       /* fall through */
-
-_GLOBAL(power7_nap)
-       mr      r4,r3
-       li      r3,PNV_THREAD_NAP
-       LOAD_REG_ADDR(r5, pnv_enter_arch207_idle_mode)
+       LOAD_REG_ADDR(r4, pnv_enter_arch207_idle_mode)
        b       pnv_powersave_common
-       /* No return */
-
-_GLOBAL(power7_sleep)
-       li      r3,PNV_THREAD_SLEEP
-       li      r4,1
-       LOAD_REG_ADDR(r5, pnv_enter_arch207_idle_mode)
-       b       pnv_powersave_common
-       /* No return */
-
-_GLOBAL(power7_winkle)
-       li      r3,PNV_THREAD_WINKLE
-       li      r4,1
-       LOAD_REG_ADDR(r5, pnv_enter_arch207_idle_mode)
-       b       pnv_powersave_common
-       /* No return */
 
 #define CHECK_HMI_INTERRUPT                                            \
-       mfspr   r0,SPRN_SRR1;                                           \
 BEGIN_FTR_SECTION_NESTED(66);                                          \
-       rlwinm  r0,r0,45-31,0xf;  /* extract wake reason field (P8) */  \
+       rlwinm  r0,r12,45-31,0xf;  /* extract wake reason field (P8) */ \
 FTR_SECTION_ELSE_NESTED(66);                                           \
-       rlwinm  r0,r0,45-31,0xe;  /* P7 wake reason field is 3 bits */  \
+       rlwinm  r0,r12,45-31,0xe;  /* P7 wake reason field is 3 bits */ \
 ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66);               \
        cmpwi   r0,0xa;                 /* Hypervisor maintenance ? */  \
-       bne     20f;                                                    \
+       bne+    20f;                                                    \
        /* Invoke opal call to handle hmi */                            \
        ld      r2,PACATOC(r13);                                        \
        ld      r1,PACAR1(r13);                                         \
@@ -369,16 +318,13 @@ ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66);          \
 20:    nop;
 
 /*
- * r3 - The PSSCR value corresponding to the stop state.
- * r4 - The PSSCR mask corrresonding to the stop state.
+ * Entered with MSR[EE]=0 and no soft-masked interrupts pending.
+ * r3 contains desired PSSCR register value.
  */
 _GLOBAL(power9_idle_stop)
-       mfspr   r5,SPRN_PSSCR
-       andc    r5,r5,r4
-       or      r3,r3,r5
+       std     r3, PACA_REQ_PSSCR(r13)
        mtspr   SPRN_PSSCR,r3
-       LOAD_REG_ADDR(r5,power_enter_stop)
-       li      r4,1
+       LOAD_REG_ADDR(r4,power_enter_stop)
        b       pnv_powersave_common
        /* No return */
 
@@ -416,7 +362,7 @@ power9_dd1_recover_paca:
         * which needs to be restored from the stack.
         */
        li      r3, 1
-       stb     r0,PACA_NAPSTATELOST(r13)
+       stb     r3,PACA_NAPSTATELOST(r13)
        blr
 
 /*
@@ -436,17 +382,17 @@ pnv_powersave_wakeup_mce:
 
        /*
         * Now put the original SRR1 with SRR1_WAKEMCE_RESVD as the wake
-        * reason into SRR1, which allows reuse of the system reset wakeup
+        * reason into r12, which allows reuse of the system reset wakeup
         * code without being mistaken for another type of wakeup.
         */
-       oris    r3,r3,SRR1_WAKEMCE_RESVD@h
-       mtspr   SPRN_SRR1,r3
+       oris    r12,r3,SRR1_WAKEMCE_RESVD@h
 
        b       pnv_powersave_wakeup
 
 /*
  * Called from reset vector for powersave wakeups.
  * cr3 - set to gt if waking up with partial/complete hypervisor state loss
+ * r12 - SRR1
  */
 .global pnv_powersave_wakeup
 pnv_powersave_wakeup:
@@ -464,6 +410,8 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_300)
        li      r0,PNV_THREAD_RUNNING
        stb     r0,PACA_THREAD_IDLE_STATE(r13)  /* Clear thread state */
 
+       mr      r3,r12
+
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
        li      r0,KVM_HWTHREAD_IN_KERNEL
        stb     r0,HSTATE_HWTHREAD_STATE(r13)
@@ -477,7 +425,6 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_300)
 #endif
 
        /* Return SRR1 from power7_nap() */
-       mfspr   r3,SPRN_SRR1
        blt     cr3,pnv_wakeup_noloss
        b       pnv_wakeup_loss
 
@@ -495,12 +442,22 @@ pnv_restore_hyp_resource_arch300:
        LOAD_REG_ADDRBASE(r5,pnv_first_deep_stop_state)
        ld      r4,ADDROFF(pnv_first_deep_stop_state)(r5)
 
-       mfspr   r5,SPRN_PSSCR
+BEGIN_FTR_SECTION_NESTED(71)
+       /*
+        * Assume that we are waking up from the state
+        * same as the Requested Level (RL) in the PSSCR
+        * which are Bits 60-63
+        */
+       ld      r5,PACA_REQ_PSSCR(r13)
+       rldicl  r5,r5,0,60
+FTR_SECTION_ELSE_NESTED(71)
        /*
         * 0-3 bits correspond to Power-Saving Level Status
         * which indicates the idle state we are waking up from
         */
+       mfspr   r5, SPRN_PSSCR
        rldicl  r5,r5,4,60
+ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_POWER9_DD1, 71)
        cmpd    cr4,r5,r4
        bge     cr4,pnv_wakeup_tb_loss /* returns to caller */
 
@@ -567,9 +524,9 @@ pnv_wakeup_tb_loss:
         * is required to return back to reset vector after hypervisor state
         * restore is complete.
         */
+       mr      r19,r12
        mr      r18,r4
        mflr    r17
-       mfspr   r16,SPRN_SRR1
 BEGIN_FTR_SECTION
        CHECK_HMI_INTERRUPT
 END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
@@ -731,13 +688,14 @@ timebase_resync:
         * Use cr3 which indicates that we are waking up with atleast partial
         * hypervisor state loss to determine if TIMEBASE RESYNC is needed.
         */
-       ble     cr3,clear_lock
+       ble     cr3,.Ltb_resynced
        /* Time base re-sync */
        bl      opal_resync_timebase;
        /*
-        * If waking up from sleep, per core state is not lost, skip to
-        * clear_lock.
+        * If waking up from sleep (POWER8), per core state
+        * is not lost, skip to clear_lock.
         */
+.Ltb_resynced:
        blt     cr4,clear_lock
 
        /*
@@ -812,9 +770,13 @@ no_segments:
        mtctr   r12
        bctrl
 
+BEGIN_FTR_SECTION
+       ld      r4,_LPCR(r1)
+       mtspr   SPRN_LPCR,r4
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
 hypervisor_state_restored:
 
-       mtspr   SPRN_SRR1,r16
+       mr      r12,r19
        mtlr    r17
        blr             /* return to pnv_powersave_wakeup */
 
@@ -827,6 +789,7 @@ fastsleep_workaround_at_exit:
 /*
  * R3 here contains the value that will be returned to the caller
  * of power7_nap.
+ * R12 contains SRR1 for CHECK_HMI_INTERRUPT.
  */
 .global pnv_wakeup_loss
 pnv_wakeup_loss:
@@ -836,32 +799,33 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
        REST_NVGPRS(r1)
        REST_GPR(2, r1)
+       ld      r4,PACAKMSR(r13)
+       ld      r5,_LINK(r1)
        ld      r6,_CCR(r1)
-       ld      r4,_MSR(r1)
-       ld      r5,_NIP(r1)
        addi    r1,r1,INT_FRAME_SIZE
+       mtlr    r5
        mtcr    r6
-       mtspr   SPRN_SRR1,r4
-       mtspr   SPRN_SRR0,r5
-       rfid
+       mtmsrd  r4
+       blr
 
 /*
  * R3 here contains the value that will be returned to the caller
  * of power7_nap.
+ * R12 contains SRR1 for CHECK_HMI_INTERRUPT.
  */
 pnv_wakeup_noloss:
        lbz     r0,PACA_NAPSTATELOST(r13)
        cmpwi   r0,0
        bne     pnv_wakeup_loss
+       ld      r1,PACAR1(r13)
 BEGIN_FTR_SECTION
        CHECK_HMI_INTERRUPT
 END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
-       ld      r1,PACAR1(r13)
-       ld      r6,_CCR(r1)
-       ld      r4,_MSR(r1)
+       ld      r4,PACAKMSR(r13)
        ld      r5,_NIP(r1)
+       ld      r6,_CCR(r1)
        addi    r1,r1,INT_FRAME_SIZE
+       mtlr    r5
        mtcr    r6
-       mtspr   SPRN_SRR1,r4
-       mtspr   SPRN_SRR0,r5
-       rfid
+       mtmsrd  r4
+       blr