Commit bc14c491 authored by Mahesh Salgaonkar's avatar Mahesh Salgaonkar Committed by Michael Ellerman

powerpc/powernv: Fix MCE handler to avoid trashing CR0/CR1 registers.

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().

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.

Fixes: 1c51089f ("powerpc/book3s: Return from interrupt if coming from evil context.")
Reported-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Reviewed-by: default avatarShreyas B. Prabhu <shreyas@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 98d8821a
...@@ -144,29 +144,14 @@ machine_check_pSeries_1: ...@@ -144,29 +144,14 @@ machine_check_pSeries_1:
* vector * vector
*/ */
SET_SCRATCH0(r13) /* save r13 */ SET_SCRATCH0(r13) /* save r13 */
#ifdef CONFIG_PPC_P7_NAP /*
BEGIN_FTR_SECTION * Running native on arch 2.06 or later, we may wakeup from winkle
/* Running native on arch 2.06 or later, check if we are * inside machine check. If yes, then last bit of HSPGR0 would be set
* waking up from nap. We only handle no state loss and * to 1. Hence clear it unconditionally.
* supervisor state loss. We do -not- handle hypervisor
* state loss at this time.
*/ */
mfspr r13,SPRN_SRR1 GET_PACA(r13)
rlwinm. r13,r13,47-31,30,31 clrrdi r13,r13,1
OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR) SET_PACA(r13)
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 */
EXCEPTION_PROLOG_0(PACA_EXMC) EXCEPTION_PROLOG_0(PACA_EXMC)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
b machine_check_powernv_early b machine_check_powernv_early
...@@ -1273,25 +1258,51 @@ machine_check_handle_early: ...@@ -1273,25 +1258,51 @@ machine_check_handle_early:
* Check if thread was in power saving mode. We come here when any * Check if thread was in power saving mode. We come here when any
* of the following is true: * of the following is true:
* a. thread wasn't in power saving mode * a. thread wasn't in power saving mode
* b. thread was in power saving mode with no state loss or * b. thread was in power saving mode with no state loss,
* supervisor 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? */ rlwinm. r11,r12,47-31,30,31 /* Was it in power saving mode? */
beq 4f /* No, it wasn;t */ beq 4f /* No, it wasn;t */
/* Thread was in power saving mode. Go back to nap again. */ /* Thread was in power saving mode. Go back to nap again. */
cmpwi r11,2 cmpwi r11,2
bne 3f blt 3f
/* Supervisor state loss */ /* Supervisor/Hypervisor state loss */
li r0,1 li r0,1
stb r0,PACA_NAPSTATELOST(r13) stb r0,PACA_NAPSTATELOST(r13)
3: bl machine_check_queue_event 3: bl machine_check_queue_event
MACHINE_CHECK_HANDLER_WINDUP MACHINE_CHECK_HANDLER_WINDUP
GET_PACA(r13) GET_PACA(r13)
ld r1,PACAR1(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: 4:
#endif #endif
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment