[PATCH v3 2/2] powernv: Fix MCE handler to avoid trashing CR0/CR1 registers.
Benjamin Herrenschmidt
benh at kernel.crashing.org
Sat Aug 6 08:39:15 AEST 2016
On Fri, 2016-08-05 at 17:34 +0530, Mahesh J Salgaonkar wrote:
> From: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>
>
> The current implementation of MCE early handling modifies CR0/1
> registers
> without saving its old values. Fix this by moving early check for
> powersaving mode to machine_check_handle_early().
CC stable ?
> The power architecture 2.06 or later allows the possibility of
> getting
> machine check while in nap/sleep/winkle. The last bit of HSPRG0 is
> set
> to 1, if thread is woken up from winkle. Hence, clear the last bit of
> HSPRG0 (r13) before MCE handler starts using it as paca pointer.
>
> Also, the current code always puts the thread into nap state
> irrespective
> of whatever idle state it woke up from. Fix that by looking at
> paca->thread_idle_state and put the thread back into same state where
> it
> came from.
>
> Reported-by: Paul Mackerras <paulus at samba.org>
> Signed-off-by: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>
> Reviewed-by: Shreyas B. Prabhu <shreyas at linux.vnet.ibm.com>
> ---
> Change in v3:
> - Rebase to Linus' master.
>
> Change in v2:
> - Call IDLE_STATE_ENTER_SEQ(PPC_NAP) instead of
> power7_enter_nap_mode()
> to be consistent with other part of code.
> ---
> arch/powerpc/kernel/exceptions-64s.S | 69 ++++++++++++++++++++--
> ------------
> 1 file changed, 40 insertions(+), 29 deletions(-)
>
> diff --git a/arch/powerpc/kernel/exceptions-64s.S
> b/arch/powerpc/kernel/exceptions-64s.S
> index 694def6..a59c9cc 100644
> --- a/arch/powerpc/kernel/exceptions-64s.S
> +++ b/arch/powerpc/kernel/exceptions-64s.S
> @@ -144,29 +144,14 @@ machine_check_pSeries_1:
> * vector
> */
> SET_SCRATCH0(r13) /* save r13 */
> -#ifdef CONFIG_PPC_P7_NAP
> -BEGIN_FTR_SECTION
> - /* Running native on arch 2.06 or later, check if we are
> - * waking up from nap. We only handle no state loss and
> - * supervisor state loss. We do -not- handle hypervisor
> - * state loss at this time.
> + /*
> + * Running native on arch 2.06 or later, we may wakeup from
> winkle
> + * inside machine check. If yes, then last bit of HSPGR0
> would be set
> + * to 1. Hence clear it unconditionally.
> */
> - mfspr r13,SPRN_SRR1
> - rlwinm. r13,r13,47-31,30,31
> - OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
> - beq 9f
> -
> - mfspr r13,SPRN_SRR1
> - rlwinm. r13,r13,47-31,30,31
> - /* waking up from powersave (nap) state */
> - cmpwi cr1,r13,2
> - /* Total loss of HV state is fatal. let's just stay stuck
> here */
> - OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
> - bgt cr1,.
> -9:
> - OPT_SET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
> -END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
> -#endif /* CONFIG_PPC_P7_NAP */
> + GET_PACA(r13)
> + clrrdi r13,r13,1
> + SET_PACA(r13)
> EXCEPTION_PROLOG_0(PACA_EXMC)
> BEGIN_FTR_SECTION
> b machine_check_powernv_early
> @@ -1273,25 +1258,51 @@ machine_check_handle_early:
> * Check if thread was in power saving mode. We come here
> when any
> * of the following is true:
> * a. thread wasn't in power saving mode
> - * b. thread was in power saving mode with no state loss or
> - * supervisor state loss
> + * b. thread was in power saving mode with no state loss,
> + * supervisor state loss or hypervisor state loss.
> *
> - * Go back to nap again if (b) is true.
> + * 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
> - bne 3f
> - /* Supervisor state loss */
> + 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)
> - li r3,PNV_THREAD_NAP
> - b pnv_enter_arch207_idle_mode
> + /*
> + * 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(PPC_NAP)
> + /* No return */
> +10:
> + cmpwi r3,PNV_THREAD_SLEEP
> + bgt 2f
> + IDLE_STATE_ENTER_SEQ(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
> HSPGR0
> + * 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(PPC_WINKLE)
> + /* No return */
> 4:
> #endif
> /*
More information about the Linuxppc-dev
mailing list