diff options
Diffstat (limited to 'arch/powerpc/kernel/idle_book3s.S')
-rw-r--r-- | arch/powerpc/kernel/idle_book3s.S | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S index 5f61cc0349c0..6fd08219248d 100644 --- a/arch/powerpc/kernel/idle_book3s.S +++ b/arch/powerpc/kernel/idle_book3s.S | |||
@@ -276,19 +276,21 @@ power_enter_stop: | |||
276 | */ | 276 | */ |
277 | andis. r4,r3,PSSCR_EC_ESL_MASK_SHIFTED | 277 | andis. r4,r3,PSSCR_EC_ESL_MASK_SHIFTED |
278 | clrldi r3,r3,60 /* r3 = Bits[60:63] = Requested Level (RL) */ | 278 | clrldi r3,r3,60 /* r3 = Bits[60:63] = Requested Level (RL) */ |
279 | bne 1f | 279 | bne .Lhandle_esl_ec_set |
280 | IDLE_STATE_ENTER_SEQ(PPC_STOP) | 280 | IDLE_STATE_ENTER_SEQ(PPC_STOP) |
281 | li r3,0 /* Since we didn't lose state, return 0 */ | 281 | li r3,0 /* Since we didn't lose state, return 0 */ |
282 | b pnv_wakeup_noloss | 282 | b pnv_wakeup_noloss |
283 | |||
284 | .Lhandle_esl_ec_set: | ||
283 | /* | 285 | /* |
284 | * Check if the requested state is a deep idle state. | 286 | * Check if the requested state is a deep idle state. |
285 | */ | 287 | */ |
286 | 1: LOAD_REG_ADDRBASE(r5,pnv_first_deep_stop_state) | 288 | LOAD_REG_ADDRBASE(r5,pnv_first_deep_stop_state) |
287 | ld r4,ADDROFF(pnv_first_deep_stop_state)(r5) | 289 | ld r4,ADDROFF(pnv_first_deep_stop_state)(r5) |
288 | cmpd r3,r4 | 290 | cmpd r3,r4 |
289 | bge 2f | 291 | bge .Lhandle_deep_stop |
290 | IDLE_STATE_ENTER_SEQ_NORET(PPC_STOP) | 292 | IDLE_STATE_ENTER_SEQ_NORET(PPC_STOP) |
291 | 2: | 293 | .Lhandle_deep_stop: |
292 | /* | 294 | /* |
293 | * Entering deep idle state. | 295 | * Entering deep idle state. |
294 | * Clear thread bit in PACA_CORE_IDLE_STATE, save SPRs to | 296 | * Clear thread bit in PACA_CORE_IDLE_STATE, save SPRs to |
@@ -447,9 +449,23 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) | |||
447 | _GLOBAL(pnv_wakeup_tb_loss) | 449 | _GLOBAL(pnv_wakeup_tb_loss) |
448 | ld r1,PACAR1(r13) | 450 | ld r1,PACAR1(r13) |
449 | /* | 451 | /* |
450 | * Before entering any idle state, the NVGPRs are saved in the stack | 452 | * Before entering any idle state, the NVGPRs are saved in the stack. |
451 | * and they are restored before switching to the process context. Hence | 453 | * If there was a state loss, or PACA_NAPSTATELOST was set, then the |
452 | * until they are restored, they are free to be used. | 454 | * NVGPRs are restored. If we are here, it is likely that state is lost, |
455 | * but not guaranteed -- neither ISA207 nor ISA300 tests to reach | ||
456 | * here are the same as the test to restore NVGPRS: | ||
457 | * PACA_THREAD_IDLE_STATE test for ISA207, PSSCR test for ISA300, | ||
458 | * and SRR1 test for restoring NVGPRs. | ||
459 | * | ||
460 | * We are about to clobber NVGPRs now, so set NAPSTATELOST to | ||
461 | * guarantee they will always be restored. This might be tightened | ||
462 | * with careful reading of specs (particularly for ISA300) but this | ||
463 | * is already a slow wakeup path and it's simpler to be safe. | ||
464 | */ | ||
465 | li r0,1 | ||
466 | stb r0,PACA_NAPSTATELOST(r13) | ||
467 | |||
468 | /* | ||
453 | * | 469 | * |
454 | * Save SRR1 and LR in NVGPRs as they might be clobbered in | 470 | * Save SRR1 and LR in NVGPRs as they might be clobbered in |
455 | * opal_call() (called in CHECK_HMI_INTERRUPT). SRR1 is required | 471 | * opal_call() (called in CHECK_HMI_INTERRUPT). SRR1 is required |