Before entering any idle state which can result in a state loss we currently save the context in the stack before entering idle. Encapsulate these steps in a macro IDLE_STATE_PREP. Move this and other macros to commonly accessible location.
Signed-off-by: Shreyas B. Prabhu <shre...@linux.vnet.ibm.com> --- arch/powerpc/include/asm/cpuidle.h | 68 ++++++++++++++++++++++++++++++++++++++ arch/powerpc/kernel/idle_power7.S | 65 ++---------------------------------- 2 files changed, 70 insertions(+), 63 deletions(-) diff --git a/arch/powerpc/include/asm/cpuidle.h b/arch/powerpc/include/asm/cpuidle.h index d2f99ca1e3a6..6c678a779e8e 100644 --- a/arch/powerpc/include/asm/cpuidle.h +++ b/arch/powerpc/include/asm/cpuidle.h @@ -15,6 +15,74 @@ extern u32 pnv_fastsleep_workaround_at_entry[]; extern u32 pnv_fastsleep_workaround_at_exit[]; #endif +/* + * IDLE_STATE_PREP - Will be called in preparation for entering + * any hardware idle state. Since idle states can result in a + * state loss, we create a regs frame on the stack, fill it up + * with the state we care about and stick a pointer to it in + * PACAR1. Use interrupt stack frame for this purpose. + * r3 - contains idle state to be entered + * r13 - PACA pointer + */ +#define IDLE_STATE_PREP \ + mflr r0; \ + std r0,16(r1); \ + stdu r1,-INT_FRAME_SIZE(r1); \ + std r0,_LINK(r1); \ + std r0,_NIP(r1); \ + \ + /* Hard disable interrupts */ \ + mfmsr r9; \ + rldicl r9,r9,48,1; \ + rotldi r9,r9,16; \ + mtmsrd r9,1; /* hard-disable interrupts */ \ + \ + /* Check if something happened while soft-disabled */ \ + lbz r0,PACAIRQHAPPENED(r13); \ + andi. r0,r0,~PACA_IRQ_HARD_DIS@l; \ + beq 1f; \ + cmpwi cr0,r4,0; \ + beq 1f; \ + addi r1,r1,INT_FRAME_SIZE; \ + ld r0,16(r1); \ + li r3,0; /* Return 0 (no nap) */ \ + mtlr r0; \ + blr; \ +1: /* We mark irqs hard disabled as this is the state \ + * we'll be in when returning and we need to tell \ + * arch_local_irq_restore() about it */ \ + li r0,PACA_IRQ_HARD_DIS; \ + stb r0,PACAIRQHAPPENED(r13); \ + \ + /* We haven't lost state ... yet */ \ + li r0,0; \ + stb r0,PACA_NAPSTATELOST(r13); \ + \ + /* Continue saving state */ \ + SAVE_GPR(2, r1); \ + SAVE_NVGPRS(r1); \ + mfcr r4; \ + std r4,_CCR(r1); \ + std r9,_MSR(r1); \ + std r1,PACAR1(r13); \ + +/* + * We use interrupt stack to save and restore few registers like + * PC, CR, LR and NVGPRs while enter/exiting idle states. Since + * volatile registers don't need to be saved/restored use that space + * instead to save/restore sprs which lose state during winkle. + */ +#define _SDR1 GPR3 +#define _RPR GPR4 +#define _SPURR GPR5 +#define _PURR GPR6 +#define _TSCR GPR7 +#define _DSCR GPR8 +#define _AMOR GPR9 +#define _WORT GPR10 +#define _WORC GPR11 + + #endif #endif diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S index abc53e88a5b4..6af57e292848 100644 --- a/arch/powerpc/kernel/idle_power7.S +++ b/arch/powerpc/kernel/idle_power7.S @@ -24,20 +24,6 @@ #undef DEBUG -/* - * Use unused space in the interrupt stack to save and restore - * registers for winkle support. - */ -#define _SDR1 GPR3 -#define _RPR GPR4 -#define _SPURR GPR5 -#define _PURR GPR6 -#define _TSCR GPR7 -#define _DSCR GPR8 -#define _AMOR GPR9 -#define _WORT GPR10 -#define _WORC GPR11 - /* Idle state entry routines */ #define IDLE_STATE_ENTER_SEQ(IDLE_INST) \ @@ -77,55 +63,8 @@ core_idle_lock_held: * 1 - check */ _GLOBAL(power7_powersave_common) - /* Use r3 to pass state nap/sleep/winkle */ - /* NAP is a state loss, we create a regs frame on the - * stack, fill it up with the state we care about and - * stick a pointer to it in PACAR1. We really only - * need to save PC, some CR bits and the NV GPRs, - * but for now an interrupt frame will do. - */ - mflr r0 - std r0,16(r1) - stdu r1,-INT_FRAME_SIZE(r1) - std r0,_LINK(r1) - std r0,_NIP(r1) - - /* Hard disable interrupts */ - mfmsr r9 - rldicl r9,r9,48,1 - rotldi r9,r9,16 - mtmsrd r9,1 /* hard-disable interrupts */ - - /* Check if something happened while soft-disabled */ - lbz r0,PACAIRQHAPPENED(r13) - andi. r0,r0,~PACA_IRQ_HARD_DIS@l - beq 1f - cmpwi cr0,r4,0 - beq 1f - addi r1,r1,INT_FRAME_SIZE - ld r0,16(r1) - li r3,0 /* Return 0 (no nap) */ - mtlr r0 - blr - -1: /* We mark irqs hard disabled as this is the state we'll - * be in when returning and we need to tell arch_local_irq_restore() - * about it - */ - li r0,PACA_IRQ_HARD_DIS - stb r0,PACAIRQHAPPENED(r13) - - /* We haven't lost state ... yet */ - li r0,0 - stb r0,PACA_NAPSTATELOST(r13) - - /* Continue saving state */ - SAVE_GPR(2, r1) - SAVE_NVGPRS(r1) - mfcr r4 - std r4,_CCR(r1) - std r9,_MSR(r1) - std r1,PACAR1(r13) + /* Save PC, CR, LR and NVGPRs in stack */ + IDLE_STATE_PREP; /* * Go to real mode to do the nap, as required by the architecture. -- 1.9.3 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev