]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - arch/powerpc/kernel/exceptions-64s.S
powerpc/64s: Fix POWER9 machine check handler from stop state
[mirror_ubuntu-bionic-kernel.git] / arch / powerpc / kernel / exceptions-64s.S
index 857bf7c5b9465aff743b3e62094cc47d808c8c92..28f8d7bed6b12a089754a753e3704160f4f52332 100644 (file)
@@ -116,9 +116,7 @@ EXC_VIRT_NONE(0x4000, 0x100)
 
 EXC_REAL_BEGIN(system_reset, 0x100, 0x100)
        SET_SCRATCH0(r13)
-       GET_PACA(r13)
-       clrrdi  r13,r13,1 /* Last bit of HSPRG0 is set if waking from winkle */
-       EXCEPTION_PROLOG_PSERIES_PACA(PACA_EXGEN, system_reset_common, EXC_STD,
+       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
                                 IDLETEST, 0x100)
 
 EXC_REAL_END(system_reset, 0x100, 0x100)
@@ -126,31 +124,7 @@ EXC_VIRT_NONE(0x4100, 0x100)
 
 #ifdef CONFIG_PPC_P7_NAP
 EXC_COMMON_BEGIN(system_reset_idle_common)
-BEGIN_FTR_SECTION
-       GET_PACA(r13) /* Restore HSPRG0 to get the winkle bit in r13 */
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
-       bl      pnv_restore_hyp_resource
-
-       li      r0,PNV_THREAD_RUNNING
-       stb     r0,PACA_THREAD_IDLE_STATE(r13)  /* Clear thread state */
-
-#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
-       li      r0,KVM_HWTHREAD_IN_KERNEL
-       stb     r0,HSTATE_HWTHREAD_STATE(r13)
-       /* Order setting hwthread_state vs. testing hwthread_req */
-       sync
-       lbz     r0,HSTATE_HWTHREAD_REQ(r13)
-       cmpwi   r0,0
-       beq     1f
-       BRANCH_TO_KVM(r10, kvm_start_guest)
-1:
-#endif
-
-       /* Return SRR1 from power7_nap() */
-       mfspr   r3,SPRN_SRR1
-       blt     cr3,2f
-       b       pnv_wakeup_loss
-2:     b       pnv_wakeup_noloss
+       b       pnv_powersave_wakeup
 #endif
 
 EXC_COMMON(system_reset_common, 0x100, system_reset_exception)
@@ -172,14 +146,6 @@ EXC_REAL_BEGIN(machine_check, 0x200, 0x100)
         * vector
         */
        SET_SCRATCH0(r13)               /* save r13 */
-       /*
-        * Running native on arch 2.06 or later, we may wakeup from winkle
-        * inside machine check. If yes, then last bit of HSPRG0 would be set
-        * to 1. Hence clear it unconditionally.
-        */
-       GET_PACA(r13)
-       clrrdi  r13,r13,1
-       SET_PACA(r13)
        EXCEPTION_PROLOG_0(PACA_EXMC)
 BEGIN_FTR_SECTION
        b       machine_check_powernv_early
@@ -212,6 +178,12 @@ BEGIN_FTR_SECTION
         * NOTE: We are here with MSR_ME=0 (off), which means we risk a
         * checkstop if we get another machine check exception before we do
         * rfid with MSR_ME=1.
+        *
+        * This interrupt can wake directly from idle. If that is the case,
+        * the machine check is handled then the idle wakeup code is called
+        * to restore state. In that case, the POWER9 DD1 idle PACA workaround
+        * is not applied in the early machine check code, which will cause
+        * bugs.
         */
        mr      r11,r1                  /* Save r1 */
        lhz     r10,PACA_IN_MCE(r13)
@@ -340,6 +312,37 @@ EXC_COMMON_BEGIN(machine_check_common)
        /* restore original r1. */                      \
        ld      r1,GPR1(r1)
 
+#ifdef CONFIG_PPC_P7_NAP
+/*
+ * This is an idle wakeup. Low level machine check has already been
+ * done. Queue the event then call the idle code to do the wake up.
+ */
+EXC_COMMON_BEGIN(machine_check_idle_common)
+       bl      machine_check_queue_event
+
+       /*
+        * We have not used any non-volatile GPRs here, and as a rule
+        * most exception code including machine check does not.
+        * Therefore PACA_NAPSTATELOST does not need to be set. Idle
+        * wakeup will restore volatile registers.
+        *
+        * Load the original SRR1 into r3 for pnv_powersave_wakeup_mce.
+        *
+        * Then decrement MCE nesting after finishing with the stack.
+        */
+       ld      r3,_MSR(r1)
+
+       lhz     r11,PACA_IN_MCE(r13)
+       subi    r11,r11,1
+       sth     r11,PACA_IN_MCE(r13)
+
+       /* Turn off the RI bit because SRR1 is used by idle wakeup code. */
+       /* Recoverability could be improved by reducing the use of SRR1. */
+       li      r11,0
+       mtmsrd  r11,1
+
+       b       pnv_powersave_wakeup_mce
+#endif
        /*
         * Handle machine check early in real mode. We come here with
         * ME=1, MMU (IR=0 and DR=0) off and using MC emergency stack.
@@ -352,6 +355,7 @@ EXC_COMMON_BEGIN(machine_check_handle_early)
        bl      machine_check_early
        std     r3,RESULT(r1)   /* Save result */
        ld      r12,_MSR(r1)
+
 #ifdef CONFIG_PPC_P7_NAP
        /*
         * Check if thread was in power saving mode. We come here when any
@@ -362,48 +366,14 @@ EXC_COMMON_BEGIN(machine_check_handle_early)
         *
         * Go back to nap/sleep/winkle mode again if (b) is true.
         */
-       rlwinm. r11,r12,47-31,30,31     /* Was it in power saving mode? */
-       beq     4f                      /* No, it wasn;t */
-       /* Thread was in power saving mode. Go back to nap again. */
-       cmpwi   r11,2
-       blt     3f
-       /* Supervisor/Hypervisor state loss */
-       li      r0,1
-       stb     r0,PACA_NAPSTATELOST(r13)
-3:     bl      machine_check_queue_event
-       MACHINE_CHECK_HANDLER_WINDUP
-       GET_PACA(r13)
-       ld      r1,PACAR1(r13)
-       /*
-        * Check what idle state this CPU was in and go back to same mode
-        * again.
-        */
-       lbz     r3,PACA_THREAD_IDLE_STATE(r13)
-       cmpwi   r3,PNV_THREAD_NAP
-       bgt     10f
-       IDLE_STATE_ENTER_SEQ_NORET(PPC_NAP)
-       /* No return */
-10:
-       cmpwi   r3,PNV_THREAD_SLEEP
-       bgt     2f
-       IDLE_STATE_ENTER_SEQ_NORET(PPC_SLEEP)
-       /* No return */
-
-2:
-       /*
-        * Go back to winkle. Please note that this thread was woken up in
-        * machine check from winkle and have not restored the per-subcore
-        * state. Hence before going back to winkle, set last bit of HSPRG0
-        * to 1. This will make sure that if this thread gets woken up
-        * again at reset vector 0x100 then it will get chance to restore
-        * the subcore state.
-        */
-       ori     r13,r13,1
-       SET_PACA(r13)
-       IDLE_STATE_ENTER_SEQ_NORET(PPC_WINKLE)
-       /* No return */
+       BEGIN_FTR_SECTION
+       rlwinm. r11,r12,47-31,30,31
+       beq-    4f
+       BRANCH_TO_COMMON(r10, machine_check_idle_common)
 4:
+       END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
 #endif
+
        /*
         * Check if we are coming from hypervisor userspace. If yes then we
         * continue in host kernel in V mode to deliver the MC event.