On Monday 23 May 2016 08:48 PM, Shreyas B. Prabhu wrote:
> POWER ISA v3 defines a new idle processor core mechanism. In summary,
>  a) new instruction named stop is added. This instruction replaces
>       instructions like nap, sleep, rvwinkle.
>  b) new per thread SPR named PSSCR is added which controls the behavior
>       of stop instruction.

Kindly expand the register name at first use like
Processor Stop Status and Control Register (PSSCR)

>
> PSSCR has following key fields

Having the PSSCR layout here will help? something like this

----------------------------------------------------------
| PLS | /// | SD | ESL | EC | PSLL | /// | TR | MTL | RL |
----------------------------------------------------------
0      4     41   42    43   44     48    54   56    60  

>       Bits 0:3  - Power-Saving Level Status. This field indicates the lowest
>       power-saving state the thread entered since stop instruction was last
>       executed.
>
>       Bit 42 - Enable State Loss
>       0 - No state is lost irrespective of other fields
>       1 - Allows state loss
>
>       Bits 44:47 - Power-Saving Level Limit
>       This limits the power-saving level that can be entered into.
>
>       Bits 60:63 - Requested Level
>       Used to specify which power-saving level must be entered on executing
>       stop instruction
>
> This patch adds support for stop instruction and PSSCR handling.
>
> Signed-off-by: Shreyas B. Prabhu <shre...@linux.vnet.ibm.com>
> ---
> Changes in v3:
> ==============
>  - Instead of introducing new file idle_power_stop.S, P9 idle support
>    is added to idle_power_common.S using CPU_FTR sections.
>  - Fixed r4 reg clobbering in power_stop0
>  - Improved comments
>
> Changes in v2:
> ==============
>  - Using CPU_FTR_ARCH_300 bit instead of CPU_FTR_STOP_INST
>
>
>  arch/powerpc/include/asm/cpuidle.h        |   2 +
>  arch/powerpc/include/asm/kvm_book3s_asm.h |   2 +-
>  arch/powerpc/include/asm/machdep.h        |   1 +
>  arch/powerpc/include/asm/opal-api.h       |  11 ++-
>  arch/powerpc/include/asm/paca.h           |   2 +
>  arch/powerpc/include/asm/ppc-opcode.h     |   4 +
>  arch/powerpc/include/asm/processor.h      |   1 +
>  arch/powerpc/include/asm/reg.h            |  11 +++
>  arch/powerpc/kernel/asm-offsets.c         |   2 +
>  arch/powerpc/kernel/idle_power_common.S   | 143 
> +++++++++++++++++++++++++++---
>  arch/powerpc/platforms/powernv/idle.c     |  82 ++++++++++++++---
>  11 files changed, 234 insertions(+), 27 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/cpuidle.h 
> b/arch/powerpc/include/asm/cpuidle.h
> index d2f99ca..3d7fc06 100644
> --- a/arch/powerpc/include/asm/cpuidle.h
> +++ b/arch/powerpc/include/asm/cpuidle.h
> @@ -13,6 +13,8 @@
>  #ifndef __ASSEMBLY__
>  extern u32 pnv_fastsleep_workaround_at_entry[];
>  extern u32 pnv_fastsleep_workaround_at_exit[];
> +
> +extern u64 pnv_first_deep_stop_state;
>  #endif
>
>  #endif
> diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h 
> b/arch/powerpc/include/asm/kvm_book3s_asm.h
> index 72b6225..d318d43 100644
> --- a/arch/powerpc/include/asm/kvm_book3s_asm.h
> +++ b/arch/powerpc/include/asm/kvm_book3s_asm.h
> @@ -162,7 +162,7 @@ struct kvmppc_book3s_shadow_vcpu {
>
>  /* Values for kvm_state */
>  #define KVM_HWTHREAD_IN_KERNEL       0
> -#define KVM_HWTHREAD_IN_NAP  1
> +#define KVM_HWTHREAD_IN_IDLE 1
>  #define KVM_HWTHREAD_IN_KVM  2
>
>  #endif /* __ASM_KVM_BOOK3S_ASM_H__ */
> diff --git a/arch/powerpc/include/asm/machdep.h 
> b/arch/powerpc/include/asm/machdep.h
> index 6bdcd0d..ae3b155 100644
> --- a/arch/powerpc/include/asm/machdep.h
> +++ b/arch/powerpc/include/asm/machdep.h
> @@ -262,6 +262,7 @@ struct machdep_calls {
>  extern void e500_idle(void);
>  extern void power4_idle(void);
>  extern void power7_idle(void);
> +extern void power_stop0(void);
>  extern void ppc6xx_idle(void);
>  extern void book3e_idle(void);
>
> diff --git a/arch/powerpc/include/asm/opal-api.h 
> b/arch/powerpc/include/asm/opal-api.h
> index 9bb8ddf..7f3f8c6 100644
> --- a/arch/powerpc/include/asm/opal-api.h
> +++ b/arch/powerpc/include/asm/opal-api.h
> @@ -162,13 +162,20 @@
>
>  /* Device tree flags */
>
> -/* Flags set in power-mgmt nodes in device tree if
> - * respective idle states are supported in the platform.
> +/*
> + * Flags set in power-mgmt nodes in device tree describing
> + * idle states that are supported in the platform.
>   */
> +
> +#define OPAL_PM_TIMEBASE_STOP                0x00000002
> +#define OPAL_PM_LOSE_HYP_CONTEXT     0x00002000
> +#define OPAL_PM_LOSE_FULL_CONTEXT    0x00004000
>  #define OPAL_PM_NAP_ENABLED          0x00010000
>  #define OPAL_PM_SLEEP_ENABLED                0x00020000
>  #define OPAL_PM_WINKLE_ENABLED               0x00040000
>  #define OPAL_PM_SLEEP_ENABLED_ER1    0x00080000 /* with workaround */
> +#define OPAL_PM_STOP_INST_FAST               0x00100000
> +#define OPAL_PM_STOP_INST_DEEP               0x00200000
>
>  /*
>   * OPAL_CONFIG_CPU_IDLE_STATE parameters
> diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
> index 546540b..ef8e342 100644
> --- a/arch/powerpc/include/asm/paca.h
> +++ b/arch/powerpc/include/asm/paca.h
> @@ -171,6 +171,8 @@ struct paca_struct {
>       /* Mask to denote subcore sibling threads */
>       u8 subcore_sibling_mask;
>  #endif
> +      /* Template for PSSCR with EC, ESL, TR, PSLL, MTL fields set */

White space at start of the comment.

> +     u64 thread_psscr;
>
>  #ifdef CONFIG_PPC_BOOK3S_64
>       /* Exclusive emergency stack pointer for machine check exception. */
> diff --git a/arch/powerpc/include/asm/ppc-opcode.h 
> b/arch/powerpc/include/asm/ppc-opcode.h
> index 1d035c1..6a8e43b 100644
> --- a/arch/powerpc/include/asm/ppc-opcode.h
> +++ b/arch/powerpc/include/asm/ppc-opcode.h
> @@ -199,6 +199,8 @@
>  #define PPC_INST_SLEEP                       0x4c0003a4
>  #define PPC_INST_WINKLE                      0x4c0003e4
>
> +#define PPC_INST_STOP                        0x4c0002e4
> +
>  /* A2 specific instructions */
>  #define PPC_INST_ERATWE                      0x7c0001a6
>  #define PPC_INST_ERATRE                      0x7c000166
> @@ -370,6 +372,8 @@
>  #define PPC_SLEEP            stringify_in_c(.long PPC_INST_SLEEP)
>  #define PPC_WINKLE           stringify_in_c(.long PPC_INST_WINKLE)
>
> +#define PPC_STOP             stringify_in_c(.long PPC_INST_STOP)
> +
>  /* BHRB instructions */
>  #define PPC_CLRBHRB          stringify_in_c(.long PPC_INST_CLRBHRB)
>  #define PPC_MFBHRBE(r, n)    stringify_in_c(.long PPC_INST_BHRBE | \
> diff --git a/arch/powerpc/include/asm/processor.h 
> b/arch/powerpc/include/asm/processor.h
> index 009fab1..7f92fc8 100644
> --- a/arch/powerpc/include/asm/processor.h
> +++ b/arch/powerpc/include/asm/processor.h
> @@ -457,6 +457,7 @@ extern int powersave_nap; /* set if nap mode can be used 
> in idle loop */
>  extern unsigned long power7_nap(int check_irq);
>  extern unsigned long power7_sleep(void);
>  extern unsigned long power7_winkle(void);
> +extern unsigned long power_stop(unsigned long state);
>  extern void flush_instruction_cache(void);
>  extern void hard_reset_now(void);
>  extern void poweroff_now(void);
> diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
> index c1e82e9..ea971b6 100644
> --- a/arch/powerpc/include/asm/reg.h
> +++ b/arch/powerpc/include/asm/reg.h
> @@ -145,6 +145,16 @@
>  #define MSR_64BIT    0
>  #endif
>
> +/* Power Management - PSSCR Fields */
> +#define PSSCR_RL_MASK                0x0000000F
> +#define PSSCR_MTL_MASK               0x000000F0
> +#define PSSCR_TR_MASK                0x00000300
> +#define PSSCR_PSLL_MASK              0x000F0000
> +#define PSSCR_EC             0x00100000
> +#define PSSCR_ESL            0x00200000
> +#define PSSCR_SD             0x00400000
> +
> +
>  /* Floating Point Status and Control Register (FPSCR) Fields */
>  #define FPSCR_FX     0x80000000      /* FPU exception summary */
>  #define FPSCR_FEX    0x40000000      /* FPU enabled exception summary */
> @@ -288,6 +298,7 @@
>  #define SPRN_PMICR   0x354   /* Power Management Idle Control Reg */
>  #define SPRN_PMSR    0x355   /* Power Management Status Reg */
>  #define SPRN_PMMAR   0x356   /* Power Management Memory Activity Register */
> +#define SPRN_PSSCR   0x357   /* Processor Stop Status and Control Register */
>  #define SPRN_PMCR    0x374   /* Power Management Control Register */
>
>  /* HFSCR and FSCR bit numbers are the same */
> diff --git a/arch/powerpc/kernel/asm-offsets.c 
> b/arch/powerpc/kernel/asm-offsets.c
> index 9ea0955..670d2a7 100644
> --- a/arch/powerpc/kernel/asm-offsets.c
> +++ b/arch/powerpc/kernel/asm-offsets.c
> @@ -779,6 +779,8 @@ int main(void)
>                       offsetof(struct paca_struct, thread_mask));
>       DEFINE(PACA_SUBCORE_SIBLING_MASK,
>                       offsetof(struct paca_struct, subcore_sibling_mask));
> +     DEFINE(PACA_THREAD_PSSCR,
> +                     offsetof(struct paca_struct, thread_psscr));
>  #endif
>
>       DEFINE(PPC_DBELL_SERVER, PPC_DBELL_SERVER);
> diff --git a/arch/powerpc/kernel/idle_power_common.S 
> b/arch/powerpc/kernel/idle_power_common.S
> index d931537..628586a 100644
> --- a/arch/powerpc/kernel/idle_power_common.S
> +++ b/arch/powerpc/kernel/idle_power_common.S
> @@ -1,5 +1,6 @@
>  /*
> - *  This file contains the power_save function for Power7 CPUs.
> + *  This file contains the idle entry/exit functions for
> + *  POWER7, POWER8 and POWER9 CPUs.
>   *
>   *  This program is free software; you can redistribute it and/or
>   *  modify it under the terms of the GNU General Public License
> @@ -20,6 +21,7 @@
>  #include <asm/opal.h>
>  #include <asm/cpuidle.h>
>  #include <asm/book3s/64/mmu-hash.h>
> +#include <asm/mmu.h>
>
>  #undef DEBUG
>
> @@ -36,6 +38,7 @@
>  #define _AMOR        GPR9
>  #define _WORT        GPR10
>  #define _WORC        GPR11
> +#define _PTCR        GPR12
>
>  /* Idle state entry routines */
>
> @@ -49,6 +52,15 @@
>       IDLE_INST;                                              \
>       b       .
>
> +/*
> + * rA - Requested stop state
> + * rB - Spare reg that can be used
> + */
> +#define PSSCR_REQUEST_STATE(rA, rB)          \
> +     ld      rB, PACA_THREAD_PSSCR(r13);     \
> +     or      rB,rB,rA;                       \
> +     mtspr   SPRN_PSSCR, rB;
> +
>       .text
>
>  /*
> @@ -60,8 +72,13 @@ save_sprs_to_stack:
>        * Note all register i.e per-core, per-subcore or per-thread is saved
>        * here since any thread in the core might wake up first
>        */
> +BEGIN_FTR_SECTION
> +     mfspr   r3,SPRN_PTCR
> +     std     r3,_PTCR(r1)
> +FTR_SECTION_ELSE
>       mfspr   r3,SPRN_SDR1
>       std     r3,_SDR1(r1)
> +ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_300)
>       mfspr   r3,SPRN_RPR
>       std     r3,_RPR(r1)
>       mfspr   r3,SPRN_SPURR
> @@ -99,7 +116,8 @@ core_idle_lock_held:
>
>  /*
>   * Pass requested state in r3:
> - *   r3 - PNV_THREAD_NAP/SLEEP/WINKLE
> + *   r3 - PNV_THREAD_NAP/SLEEP/WINKLE in POWER8
> + *      - Requested STOP state in POWER9
>   *
>   * To check IRQ_HAPPENED in r4
>   *   0 - don't check
> @@ -160,7 +178,7 @@ _GLOBAL(pnv_powersave_common)
>
>  #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
>       /* Tell KVM we're napping */
> -     li      r4,KVM_HWTHREAD_IN_NAP
> +     li      r4,KVM_HWTHREAD_IN_IDLE
>       stb     r4,HSTATE_HWTHREAD_STATE(r13)
>  #endif
>       /*
> @@ -241,6 +259,41 @@ enter_winkle:
>
>       IDLE_STATE_ENTER_SEQ(PPC_WINKLE)
>
> +/*
> + * r3 - requested stop state
> + */
> +power_enter_stop:
> +/*
> + * Check if the requested state is a deep idle state.
> + */
> +     LOAD_REG_ADDRBASE(r5,pnv_first_deep_stop_state)
> +     ld      r4,ADDROFF(pnv_first_deep_stop_state)(r5)
> +     cmpd    r3,r4
> +     bge     2f
> +     IDLE_STATE_ENTER_SEQ(PPC_STOP)
> +2:
> +/*
> + * Entering deep idle state.
> + * Clear thread bit in PACA_CORE_IDLE_STATE, save SPRs to
> + * stack and enter stop
> + */
> +     lbz     r7,PACA_THREAD_MASK(r13)
> +     ld      r14,PACA_CORE_IDLE_STATE_PTR(r13)
> +
> +lwarx_loop_stop:
> +     lwarx   r15,0,r14
> +     andi.   r9,r15,PNV_CORE_IDLE_LOCK_BIT
> +     bnel    core_idle_lock_held
> +     andc    r15,r15,r7                      /* Clear thread bit */
> +
> +     stwcx.  r15,0,r14
> +     bne-    lwarx_loop_stop
> +     isync
> +
> +     bl      save_sprs_to_stack
> +
> +     IDLE_STATE_ENTER_SEQ(PPC_STOP)
> +
>  _GLOBAL(power7_idle)
>       /* Now check if user or arch enabled NAP mode */
>       LOAD_REG_ADDRBASE(r3,powersave_nap)
> @@ -291,6 +344,21 @@ ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66); 
>         \
>
>
>  /*
> + * r3 - requested stop state
> + */
> +_GLOBAL(power_stop)
> +     PSSCR_REQUEST_STATE(r3,r4)
> +     li      r4, 1
> +     LOAD_REG_ADDR(r5,power_enter_stop)
> +     b       pnv_powersave_common
> +     /* No return */
> +

Can you add comments here to say why we
need power_stop0?

> +_GLOBAL(power_stop0)
> +     li      r3,0
> +     b       power_stop
> +     /* No return */
> +
> +/*
>   * Called from reset vector. Check whether we have woken up with
>   * hypervisor state loss. If yes, restore hypervisor state and return
>   * back to reset vector.
> @@ -299,7 +367,32 @@ ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66); 
>         \
>   * cr3 - set to gt if waking up with partial/complete hypervisor state loss
>   */
>  _GLOBAL(pnv_restore_hyp_resource)
> +BEGIN_FTR_SECTION
> +     /*
> +      * POWER ISA 3. Use PSSCR to determine if we
> +      * are waking up from deep idle state
> +      */
> +     LOAD_REG_ADDRBASE(r5,pnv_first_deep_stop_state)
> +     ld      r4,ADDROFF(pnv_first_deep_stop_state)(r5)
> +
> +     mfspr   r5,SPRN_PSSCR
> +     /*
> +      * 0-4 bits correspond to Power-Saving Level Status

PSL is bits 0-3 of PSSCR right?


> +      * which indicates the idle state we are waking up from
> +      */
> +     rldicl  r5,r5,4,60
> +     cmpd    cr4,r5,r4
> +     bge     cr4,pnv_wakeup_tb_loss
> +     /*
> +      * Waking up without hypervisor state loss. Return to
> +      * reset vector
> +      */
> +     blr
> +
> +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
> +
>       /*
> +      * POWER ISA 2.07 or less.
>        * Check if last bit of HSPGR0 is set. This indicates whether we are
>        * waking up from winkle.
>        */
> @@ -322,7 +415,16 @@ _GLOBAL(pnv_restore_hyp_resource)
>       blr     /* Return back to System Reset vector from where
>                  pnv_restore_hyp_resource was invoked */
>
> -
> +/*
> + * Called if waking up from idle state which can cause either partial or
> + * complete hyp state loss.
> + * In POWER8, called if waking up from fastsleep or winkle
> + * In POWER9, called if waking up from stop state >= 
> pnv_first_deep_stop_state
> + *
> + * r13 - PACA
> + * cr3 - gt if waking up with partial/complete hypervisor state loss
> + * cr4 - eq if waking up from complete hypervisor state loss.
> + */
>  _GLOBAL(pnv_wakeup_tb_loss)
>       ld      r2,PACATOC(r13);
>       ld      r1,PACAR1(r13)
> @@ -365,10 +467,10 @@ lwarx_loop2:
>
>       /*
>        * At this stage
> -      * cr1 - 0b0100 if first thread to wakeup in subcore
> -      * cr2 - 0b0100 if first thread to wakeup in core
> -      * cr3-  0b0010 if waking up from sleep or winkle
> -      * cr4 - 0b0100 if waking up from winkle
> +      * cr1 - eq if first thread to wakeup in subcore
> +      * cr2 - eq if first thread to wakeup in core
> +      * cr3-  gt if waking up with partial/complete hypervisor state loss
> +      * cr4 - eq if waking up from complete hypervisor state loss.
>        */
>
>       or      r15,r15,r7              /* Set thread bit */
> @@ -395,8 +497,11 @@ first_thread_in_subcore:
>       bne     cr4,subcore_state_restored
>
>       /* Restore per-subcore state */
> +BEGIN_FTR_SECTION
>       ld      r4,_SDR1(r1)
>       mtspr   SPRN_SDR1,r4
> +END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
> +
>       ld      r4,_RPR(r1)
>       mtspr   SPRN_RPR,r4
>       ld      r4,_AMOR(r1)
> @@ -412,7 +517,8 @@ subcore_state_restored:
>  first_thread_in_core:
>
>       /*
> -      * First thread in the core waking up from fastsleep. It needs to
> +      * First thread in the core waking up from any state which can cause
> +      * partial or complete hypervisor state loss. It needs to
>        * call the fastsleep workaround code if the platform requires it.
>        * Call it unconditionally here. The below branch instruction will
>        * be patched out when the idle states are discovered if platform
> @@ -423,8 +529,10 @@ pnv_fastsleep_workaround_at_exit:
>       b       fastsleep_workaround_at_exit
>
>  timebase_resync:
> -     /* Do timebase resync if we are waking up from sleep. Use cr3 value
> -      * set in exceptions-64s.S */
> +     /*
> +      * Use cr3 which indicates that we are waking up with atleast partial
> +      * hypervisor state loss to determine if TIMEBASE RESYNC is needed.
> +      */
>       ble     cr3,clear_lock
>       /* Time base re-sync */
>       li      r0,OPAL_RESYNC_TIMEBASE
> @@ -437,7 +545,16 @@ timebase_resync:
>        */
>       bne     cr4,clear_lock
>
> -     /* Restore per core state */
> +     /*
> +      * First thread in the core to wake up and its waking up with
> +      * complete hypervisor state loss. Restore per core hypervisor
> +      * state.
> +      */
> +BEGIN_FTR_SECTION
> +     ld      r4,_PTCR(r1)
> +     mtspr   SPRN_PTCR,r4
> +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
> +
>       ld      r4,_TSCR(r1)
>       mtspr   SPRN_TSCR,r4
>       ld      r4,_WORC(r1)
> @@ -462,6 +579,7 @@ common_exit:
>       /* Restore per thread state */
>       bl      __restore_cpu_power8
>
> +BEGIN_MMU_FTR_SECTION
>       /* Restore SLB  from PACA */
>       ld      r8,PACA_SLBSHADOWPTR(r13)
>
> @@ -475,6 +593,7 @@ common_exit:
>       slbmte  r6,r5
>  1:   addi    r8,r8,16
>       .endr
> +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_RADIX)
>
>       ld      r4,_SPURR(r1)
>       mtspr   SPRN_SPURR,r4
> diff --git a/arch/powerpc/platforms/powernv/idle.c 
> b/arch/powerpc/platforms/powernv/idle.c
> index fbb09fb..989cf5d 100644
> --- a/arch/powerpc/platforms/powernv/idle.c
> +++ b/arch/powerpc/platforms/powernv/idle.c
> @@ -29,7 +29,7 @@
>
>  static u32 supported_cpuidle_states;
>
> -int pnv_save_sprs_for_winkle(void)
> +int pnv_save_sprs_for_deep_states(void)
>  {
>       int cpu;
>       int rc;
> @@ -50,15 +50,19 @@ int pnv_save_sprs_for_winkle(void)
>               uint64_t pir = get_hard_smp_processor_id(cpu);
>               uint64_t hsprg0_val = (uint64_t)&paca[cpu];
>
> -             /*
> -              * HSPRG0 is used to store the cpu's pointer to paca. Hence last
> -              * 3 bits are guaranteed to be 0. Program slw to restore HSPRG0
> -              * with 63rd bit set, so that when a thread wakes up at 0x100 we
> -              * can use this bit to distinguish between fastsleep and
> -              * deep winkle.
> -              */
> -             hsprg0_val |= 1;
> -
> +             if (!cpu_has_feature(CPU_FTR_ARCH_300)) {
> +                     /*
> +                      * HSPRG0 is used to store the cpu's pointer to paca.
> +                      * Hence last 3 bits are guaranteed to be 0. Program
> +                      * slw to restore HSPRG0 with 63rd bit set, so that
> +                      * when a thread wakes up at 0x100 we can use this bit
> +                      * to distinguish between fastsleep and deep winkle.
> +                      * This is not necessary with stop/psscr since PLS
> +                      * field of psscr indicates which state we are waking
> +                      * up from.
> +                      */
> +                     hsprg0_val |= 1;
> +             }
>               rc = opal_slw_set_reg(pir, SPRN_HSPRG0, hsprg0_val);
>               if (rc != 0)
>                       return rc;
> @@ -130,8 +134,8 @@ static void pnv_alloc_idle_core_states(void)
>
>       update_subcore_sibling_mask();
>
> -     if (supported_cpuidle_states & OPAL_PM_WINKLE_ENABLED)
> -             pnv_save_sprs_for_winkle();
> +     if (supported_cpuidle_states & OPAL_PM_LOSE_FULL_CONTEXT)
> +             pnv_save_sprs_for_deep_states();
>  }
>
>  u32 pnv_get_supported_cpuidle_states(void)
> @@ -230,11 +234,18 @@ static DEVICE_ATTR(fastsleep_workaround_applyonce, 0600,
>                       show_fastsleep_workaround_applyonce,
>                       store_fastsleep_workaround_applyonce);
>
> +/*
> + * First deep stop state. Used to figure out when to save/restore
> + * hypervisor context.
> + */
> +u64 pnv_first_deep_stop_state;
> +
>  static int __init pnv_init_idle_states(void)
>  {
>       struct device_node *power_mgt;
>       int dt_idle_states;
>       u32 *flags;
> +     u64 *psscr_val = NULL;
>       int i;
>
>       supported_cpuidle_states = 0;
> @@ -264,6 +275,32 @@ static int __init pnv_init_idle_states(void)
>               goto out_free;
>       }
>
> +     if (cpu_has_feature(CPU_FTR_ARCH_300)) {
> +             psscr_val = kcalloc(dt_idle_states, sizeof(*psscr_val),
> +                                     GFP_KERNEL);
> +             if (!psscr_val)
> +                     goto out_free;
> +             if (of_property_read_u64_array(power_mgt,
> +                     "ibm,cpu-idle-state-psscr",
> +                     psscr_val, dt_idle_states)) {
> +                     pr_warn("cpuidle-powernv: missing 
> ibm,cpu-idle-states-psscr in DT\n");
> +                     goto out_free_psscr;
> +             }
> +
> +             /*
> +              * Set pnv_first_deep_stop_state to the first stop level
> +              * to cause hypervisor state loss
> +              */
> +             pnv_first_deep_stop_state = 0xF;
> +             for (i = 0; i < dt_idle_states; i++) {
> +                     u64 psscr_rl = psscr_val[i] & PSSCR_RL_MASK;
> +
> +                     if ((flags[i] & OPAL_PM_LOSE_FULL_CONTEXT) &&
> +                          (pnv_first_deep_stop_state > psscr_rl))
> +                             pnv_first_deep_stop_state = psscr_rl;
> +             }
> +     }
> +
>       for (i = 0; i < dt_idle_states; i++)
>               supported_cpuidle_states |= flags[i];
>
> @@ -286,8 +323,29 @@ static int __init pnv_init_idle_states(void)
>
>       pnv_alloc_idle_core_states();
>
> +     if (supported_cpuidle_states & OPAL_PM_STOP_INST_FAST)
> +             for_each_possible_cpu(i) {
> +
> +                     u64 psscr_init_val = PSSCR_ESL | PSSCR_EC |
> +                                     PSSCR_PSLL_MASK | PSSCR_TR_MASK |
> +                                     PSSCR_MTL_MASK;
> +
> +                     paca[i].thread_psscr = psscr_init_val;
> +                     /*
> +                      * Memory barrier to ensure that the writes to PACA
> +                      * goes through before ppc_md.power_save is updated
> +                      * below.
> +                      */
> +                     mb();
> +             }
> +
>       if (supported_cpuidle_states & OPAL_PM_NAP_ENABLED)
>               ppc_md.power_save = power7_idle;
> +     else if (supported_cpuidle_states & OPAL_PM_STOP_INST_FAST)
> +             ppc_md.power_save = power_stop0;
> +
> +out_free_psscr:
> +     kfree(psscr_val);
>  out_free:
>       kfree(flags);
>  out:

Reply via email to