linux/arch/powerpc/kernel/idle_book3s.S
Nicholas Piggin ed0bc98f8c powerpc/64s: Reimplement power4_idle code in C
This implements the tricky tracing and soft irq handling bits in C,
leaving the low level bit to asm.

A functional difference is that this redirects the interrupt exit to
a return stub to execute blr, rather than the lr address itself. This
is probably barely measurable on real hardware, but it keeps the link
stack balanced.

Tested with QEMU.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[mpe: Move power4_fixup_nap back into exceptions-64s.S]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20190711022404.18132-1-npiggin@gmail.com
2020-01-16 14:59:37 +10:00

205 lines
5.0 KiB
ArmAsm

/* 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