Skip to content

Commit bc14c49

Browse files
maheshsalmpe
authored andcommitted
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: 1c51089 ("powerpc/book3s: Return from interrupt if coming from evil context.") Reported-by: Paul Mackerras <[email protected]> Signed-off-by: Mahesh Salgaonkar <[email protected]> Reviewed-by: Shreyas B. Prabhu <[email protected]> Signed-off-by: Michael Ellerman <[email protected]>
1 parent 98d8821 commit bc14c49

File tree

1 file changed

+40
-29
lines changed

1 file changed

+40
-29
lines changed

arch/powerpc/kernel/exceptions-64s.S

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -144,29 +144,14 @@ machine_check_pSeries_1:
144144
* vector
145145
*/
146146
SET_SCRATCH0(r13) /* save r13 */
147-
#ifdef CONFIG_PPC_P7_NAP
148-
BEGIN_FTR_SECTION
149-
/* Running native on arch 2.06 or later, check if we are
150-
* waking up from nap. We only handle no state loss and
151-
* supervisor state loss. We do -not- handle hypervisor
152-
* state loss at this time.
147+
/*
148+
* Running native on arch 2.06 or later, we may wakeup from winkle
149+
* inside machine check. If yes, then last bit of HSPGR0 would be set
150+
* to 1. Hence clear it unconditionally.
153151
*/
154-
mfspr r13,SPRN_SRR1
155-
rlwinm. r13,r13,47-31,30,31
156-
OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
157-
beq 9f
158-
159-
mfspr r13,SPRN_SRR1
160-
rlwinm. r13,r13,47-31,30,31
161-
/* waking up from powersave (nap) state */
162-
cmpwi cr1,r13,2
163-
/* Total loss of HV state is fatal. let's just stay stuck here */
164-
OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
165-
bgt cr1,.
166-
9:
167-
OPT_SET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
168-
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
169-
#endif /* CONFIG_PPC_P7_NAP */
152+
GET_PACA(r13)
153+
clrrdi r13,r13,1
154+
SET_PACA(r13)
170155
EXCEPTION_PROLOG_0(PACA_EXMC)
171156
BEGIN_FTR_SECTION
172157
b machine_check_powernv_early
@@ -1273,25 +1258,51 @@ machine_check_handle_early:
12731258
* Check if thread was in power saving mode. We come here when any
12741259
* of the following is true:
12751260
* a. thread wasn't in power saving mode
1276-
* b. thread was in power saving mode with no state loss or
1277-
* supervisor state loss
1261+
* b. thread was in power saving mode with no state loss,
1262+
* supervisor state loss or hypervisor state loss.
12781263
*
1279-
* Go back to nap again if (b) is true.
1264+
* Go back to nap/sleep/winkle mode again if (b) is true.
12801265
*/
12811266
rlwinm. r11,r12,47-31,30,31 /* Was it in power saving mode? */
12821267
beq 4f /* No, it wasn;t */
12831268
/* Thread was in power saving mode. Go back to nap again. */
12841269
cmpwi r11,2
1285-
bne 3f
1286-
/* Supervisor state loss */
1270+
blt 3f
1271+
/* Supervisor/Hypervisor state loss */
12871272
li r0,1
12881273
stb r0,PACA_NAPSTATELOST(r13)
12891274
3: bl machine_check_queue_event
12901275
MACHINE_CHECK_HANDLER_WINDUP
12911276
GET_PACA(r13)
12921277
ld r1,PACAR1(r13)
1293-
li r3,PNV_THREAD_NAP
1294-
b pnv_enter_arch207_idle_mode
1278+
/*
1279+
* Check what idle state this CPU was in and go back to same mode
1280+
* again.
1281+
*/
1282+
lbz r3,PACA_THREAD_IDLE_STATE(r13)
1283+
cmpwi r3,PNV_THREAD_NAP
1284+
bgt 10f
1285+
IDLE_STATE_ENTER_SEQ(PPC_NAP)
1286+
/* No return */
1287+
10:
1288+
cmpwi r3,PNV_THREAD_SLEEP
1289+
bgt 2f
1290+
IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
1291+
/* No return */
1292+
1293+
2:
1294+
/*
1295+
* Go back to winkle. Please note that this thread was woken up in
1296+
* machine check from winkle and have not restored the per-subcore
1297+
* state. Hence before going back to winkle, set last bit of HSPGR0
1298+
* to 1. This will make sure that if this thread gets woken up
1299+
* again at reset vector 0x100 then it will get chance to restore
1300+
* the subcore state.
1301+
*/
1302+
ori r13,r13,1
1303+
SET_PACA(r13)
1304+
IDLE_STATE_ENTER_SEQ(PPC_WINKLE)
1305+
/* No return */
12951306
4:
12961307
#endif
12971308
/*

0 commit comments

Comments
 (0)