| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| /* |
| * Copyright 2018, IBM Corporation. |
| * |
| * This file contains general idle entry/exit functions to save |
| * and restore stack and NVGPRs which allows C code to call idle |
| * states that lose GPRs, and it will return transparently with |
| * SRR1 wakeup reason return value. |
| * |
| * The platform / CPU caller must ensure SPRs and any other non-GPR |
| * state is saved and restored correctly, handle KVM, interrupts, etc. |
| */ |
| |
| #include <asm/ppc_asm.h> |
| #include <asm/asm-offsets.h> |
| #include <asm/ppc-opcode.h> |
| #include <asm/cpuidle.h> |
| #include <asm/thread_info.h> /* TLF_NAPPING */ |
| |
| #ifdef CONFIG_PPC_P7_NAP |
| /* |
| * Desired PSSCR in r3 |
| * |
| * No state will be lost regardless of wakeup mechanism (interrupt or NIA). |
| * |
| * An EC=0 type wakeup will return with a value of 0. SRESET wakeup (which can |
| * happen with xscom SRESET and possibly MCE) may clobber volatiles except LR, |
| * and must blr, to return to caller with r3 set according to caller's expected |
| * return code (for Book3S/64 that is SRR1). |
| */ |
| _GLOBAL(isa300_idle_stop_noloss) |
| mtspr SPRN_PSSCR,r3 |
| PPC_STOP |
| li r3,0 |
| blr |
| |
| /* |
| * Desired PSSCR in r3 |
| * |
| * GPRs may be lost, so they are saved here. Wakeup is by interrupt only. |
| * The SRESET wakeup returns to this function's caller by calling |
| * idle_return_gpr_loss with r3 set to desired return value. |
| * |
| * A wakeup without GPR loss may alteratively be handled as in |
| * isa300_idle_stop_noloss and blr directly, as an optimisation. |
| * |
| * The caller is responsible for saving/restoring SPRs, MSR, timebase, |
| * etc. |
| */ |
| _GLOBAL(isa300_idle_stop_mayloss) |
| mtspr SPRN_PSSCR,r3 |
| std r1,PACAR1(r13) |
| mflr r4 |
| mfcr r5 |
| /* use stack red zone rather than a new frame for saving regs */ |
| std r2,-8*0(r1) |
| std r14,-8*1(r1) |
| std r15,-8*2(r1) |
| std r16,-8*3(r1) |
| std r17,-8*4(r1) |
| std r18,-8*5(r1) |
| std r19,-8*6(r1) |
| std r20,-8*7(r1) |
| std r21,-8*8(r1) |
| std r22,-8*9(r1) |
| std r23,-8*10(r1) |
| std r24,-8*11(r1) |
| std r25,-8*12(r1) |
| std r26,-8*13(r1) |
| std r27,-8*14(r1) |
| std r28,-8*15(r1) |
| std r29,-8*16(r1) |
| std r30,-8*17(r1) |
| std r31,-8*18(r1) |
| std r4,-8*19(r1) |
| std r5,-8*20(r1) |
| /* 168 bytes */ |
| PPC_STOP |
| b . /* catch bugs */ |
| |
| /* |
| * Desired return value in r3 |
| * |
| * The idle wakeup SRESET interrupt can call this after calling |
| * to return to the idle sleep function caller with r3 as the return code. |
| * |
| * This must not be used if idle was entered via a _noloss function (use |
| * a simple blr instead). |
| */ |
| _GLOBAL(idle_return_gpr_loss) |
| ld r1,PACAR1(r13) |
| ld r4,-8*19(r1) |
| ld r5,-8*20(r1) |
| mtlr r4 |
| mtcr r5 |
| /* |
| * KVM nap requires r2 to be saved, rather than just restoring it |
| * from PACATOC. This could be avoided for that less common case |
| * if KVM saved its r2. |
| */ |
| ld r2,-8*0(r1) |
| ld r14,-8*1(r1) |
| ld r15,-8*2(r1) |
| ld r16,-8*3(r1) |
| ld r17,-8*4(r1) |
| ld r18,-8*5(r1) |
| ld r19,-8*6(r1) |
| ld r20,-8*7(r1) |
| ld r21,-8*8(r1) |
| ld r22,-8*9(r1) |
| ld r23,-8*10(r1) |
| ld r24,-8*11(r1) |
| ld r25,-8*12(r1) |
| ld r26,-8*13(r1) |
| ld r27,-8*14(r1) |
| ld r28,-8*15(r1) |
| ld r29,-8*16(r1) |
| ld r30,-8*17(r1) |
| ld r31,-8*18(r1) |
| blr |
| |
| /* |
| * This is the sequence required to execute idle instructions, as |
| * specified in ISA v2.07 (and earlier). MSR[IR] and MSR[DR] must be 0. |
| * |
| * The 0(r1) slot is used to save r2 in isa206, so use that here. |
| */ |
| #define IDLE_STATE_ENTER_SEQ_NORET(IDLE_INST) \ |
| /* Magic NAP/SLEEP/WINKLE mode enter sequence */ \ |
| std r2,0(r1); \ |
| ptesync; \ |
| ld r2,0(r1); \ |
| 236: cmpd cr0,r2,r2; \ |
| bne 236b; \ |
| IDLE_INST; \ |
| b . /* catch bugs */ |
| |
| /* |
| * Desired instruction type in r3 |
| * |
| * GPRs may be lost, so they are saved here. Wakeup is by interrupt only. |
| * The SRESET wakeup returns to this function's caller by calling |
| * idle_return_gpr_loss with r3 set to desired return value. |
| * |
| * A wakeup without GPR loss may alteratively be handled as in |
| * isa300_idle_stop_noloss and blr directly, as an optimisation. |
| * |
| * The caller is responsible for saving/restoring SPRs, MSR, timebase, |
| * etc. |
| * |
| * This must be called in real-mode (MSR_IDLE). |
| */ |
| _GLOBAL(isa206_idle_insn_mayloss) |
| std r1,PACAR1(r13) |
| mflr r4 |
| mfcr r5 |
| /* use stack red zone rather than a new frame for saving regs */ |
| std r2,-8*0(r1) |
| std r14,-8*1(r1) |
| std r15,-8*2(r1) |
| std r16,-8*3(r1) |
| std r17,-8*4(r1) |
| std r18,-8*5(r1) |
| std r19,-8*6(r1) |
| std r20,-8*7(r1) |
| std r21,-8*8(r1) |
| std r22,-8*9(r1) |
| std r23,-8*10(r1) |
| std r24,-8*11(r1) |
| std r25,-8*12(r1) |
| std r26,-8*13(r1) |
| std r27,-8*14(r1) |
| std r28,-8*15(r1) |
| std r29,-8*16(r1) |
| std r30,-8*17(r1) |
| std r31,-8*18(r1) |
| std r4,-8*19(r1) |
| std r5,-8*20(r1) |
| cmpwi r3,PNV_THREAD_NAP |
| bne 1f |
| IDLE_STATE_ENTER_SEQ_NORET(PPC_NAP) |
| 1: cmpwi r3,PNV_THREAD_SLEEP |
| bne 2f |
| IDLE_STATE_ENTER_SEQ_NORET(PPC_SLEEP) |
| 2: IDLE_STATE_ENTER_SEQ_NORET(PPC_WINKLE) |
| #endif |
| |
| #ifdef CONFIG_PPC_970_NAP |
| _GLOBAL(power4_idle_nap) |
| LOAD_REG_IMMEDIATE(r7, MSR_KERNEL|MSR_EE|MSR_POW) |
| ld r9,PACA_THREAD_INFO(r13) |
| ld r8,TI_LOCAL_FLAGS(r9) |
| ori r8,r8,_TLF_NAPPING |
| std r8,TI_LOCAL_FLAGS(r9) |
| /* |
| * NAPPING bit is set, from this point onward power4_fixup_nap |
| * will cause exceptions to return to power4_idle_nap_return. |
| */ |
| 1: sync |
| isync |
| mtmsrd r7 |
| isync |
| b 1b |
| #endif |