On Fri, 21 Jul 2017 16:11:37 +0530
"Gautham R. Shenoy" <e...@linux.vnet.ibm.com> wrote:

> From: "Gautham R. Shenoy" <e...@linux.vnet.ibm.com>
> 
> The stop4 idle state on POWER9 is a deep idle state which loses
> hypervisor resources, but whose latency is low enough that it can be
> exposed via cpuidle.
> 
> Until now, the deep idle states which lose hypervisor resources (eg:
> winkle) were only exposed via CPU-Hotplug.  Hence currently on wakeup
> from such states, barring a few SPRs which need to be restored to
> their older value, rest of the SPRS are reinitialized to their values
> corresponding to that at boot time.
> 
> When stop4 is used in the context of cpuidle, we want these additional
> SPRs to be restored to their older value, to ensure that the context
> on the CPU coming back from idle is same as it was before going idle.
> 
> In this patch, we define a SPR save area in PACA (since we have used
> up the volatile register space in the stack) and on POWER9, we restore
> SPRN_PID, SPRN_LDBAR, SPRN_FSCR, SPRN_HFSCR, SPRN_MMCRA, SPRN_MMCR1,
> SPRN_MMCR2 to the values they had before entering stop.
> 
> Signed-off-by: Gautham R. Shenoy <e...@linux.vnet.ibm.com>

Looks good to me. Keeping in mind we need to tidy up and unify
all this SPR handling and save/restore etc. in the longer term.

Reviewed-by: Nicholas Piggin <npig...@gmail.com>

> ---
> v2-->v3:
> - Use a structure instead of an array for the stop sprs save area.
> - Name the offsets into the paca->stop_sprs as STOP_XXX instead of
>   PACA_XXX.
> - Add comments in the assembly code explaining why saving/restoring
>   is not needed on POWER8.
> v1-->v2:
> No change
> 
>  arch/powerpc/include/asm/cpuidle.h | 11 +++++++
>  arch/powerpc/include/asm/paca.h    |  7 ++++
>  arch/powerpc/kernel/asm-offsets.c  |  8 +++++
>  arch/powerpc/kernel/idle_book3s.S  | 65 
> ++++++++++++++++++++++++++++++++++++--
>  4 files changed, 89 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/cpuidle.h 
> b/arch/powerpc/include/asm/cpuidle.h
> index 52586f9..8a174cb 100644
> --- a/arch/powerpc/include/asm/cpuidle.h
> +++ b/arch/powerpc/include/asm/cpuidle.h
> @@ -67,6 +67,17 @@
>  #define ERR_DEEP_STATE_ESL_MISMATCH  -2
>  
>  #ifndef __ASSEMBLY__
> +/* Additional SPRs that need to be saved/restored during stop */
> +struct stop_sprs {
> +     u64 pid;
> +     u64 ldbar;
> +     u64 fscr;
> +     u64 hfscr;
> +     u64 mmcr1;
> +     u64 mmcr2;
> +     u64 mmcra;
> +};
> +
>  extern u32 pnv_fastsleep_workaround_at_entry[];
>  extern u32 pnv_fastsleep_workaround_at_exit[];
>  
> diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
> index dc88a31..04b60af 100644
> --- a/arch/powerpc/include/asm/paca.h
> +++ b/arch/powerpc/include/asm/paca.h
> @@ -31,6 +31,7 @@
>  #endif
>  #include <asm/accounting.h>
>  #include <asm/hmi.h>
> +#include <asm/cpuidle.h>
>  
>  register struct paca_struct *local_paca asm("r13");
>  
> @@ -183,6 +184,12 @@ struct paca_struct {
>       struct paca_struct **thread_sibling_pacas;
>       /* The PSSCR value that the kernel requested before going to stop */
>       u64 requested_psscr;
> +
> +     /*
> +      * Save area for additional SPRs that need to be
> +      * saved/restored during cpuidle stop.
> +      */
> +     struct stop_sprs stop_sprs;
>  #endif
>  
>  #ifdef CONFIG_PPC_STD_MMU_64
> diff --git a/arch/powerpc/kernel/asm-offsets.c 
> b/arch/powerpc/kernel/asm-offsets.c
> index a7b5af3..e2a48df 100644
> --- a/arch/powerpc/kernel/asm-offsets.c
> +++ b/arch/powerpc/kernel/asm-offsets.c
> @@ -743,6 +743,14 @@ int main(void)
>       OFFSET(PACA_SUBCORE_SIBLING_MASK, paca_struct, subcore_sibling_mask);
>       OFFSET(PACA_SIBLING_PACA_PTRS, paca_struct, thread_sibling_pacas);
>       OFFSET(PACA_REQ_PSSCR, paca_struct, requested_psscr);
> +#define STOP_SPR(x, f)       OFFSET(x, paca_struct, stop_sprs.f)
> +     STOP_SPR(STOP_PID, pid);
> +     STOP_SPR(STOP_LDBAR, ldbar);
> +     STOP_SPR(STOP_FSCR, fscr);
> +     STOP_SPR(STOP_HFSCR, hfscr);
> +     STOP_SPR(STOP_MMCR1, mmcr1);
> +     STOP_SPR(STOP_MMCR2, mmcr2);
> +     STOP_SPR(STOP_MMCRA, mmcra);
>  #endif
>  
>       DEFINE(PPC_DBELL_SERVER, PPC_DBELL_SERVER);
> diff --git a/arch/powerpc/kernel/idle_book3s.S 
> b/arch/powerpc/kernel/idle_book3s.S
> index 5adb390e..5e6af97 100644
> --- a/arch/powerpc/kernel/idle_book3s.S
> +++ b/arch/powerpc/kernel/idle_book3s.S
> @@ -84,7 +84,61 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_300)
>       std     r3,_WORT(r1)
>       mfspr   r3,SPRN_WORC
>       std     r3,_WORC(r1)
> +/*
> + * On POWER9, there are idle states such as stop4, invoked via cpuidle,
> + * that lose hypervisor resources. In such cases, we need to save
> + * additional SPRs before entering those idle states so that they can
> + * be restored to their older values on wakeup from the idle state.
> + *
> + * On POWER8, the only such deep idle state is winkle which is used
> + * only in the context of CPU-Hotplug, where these additional SPRs are
> + * reinitiazed to a sane value. Hence there is no need to save/restore
> + * these SPRs.
> + */
> +BEGIN_FTR_SECTION
> +     blr
> +END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
> +
> +power9_save_additional_sprs:
> +     mfspr   r3, SPRN_PID
> +     mfspr   r4, SPRN_LDBAR
> +     std     r3, STOP_PID(r13)
> +     std     r4, STOP_LDBAR(r13)
>  
> +     mfspr   r3, SPRN_FSCR
> +     mfspr   r4, SPRN_HFSCR
> +     std     r3, STOP_FSCR(r13)
> +     std     r4, STOP_HFSCR(r13)
> +
> +     mfspr   r3, SPRN_MMCRA
> +     mfspr   r4, SPRN_MMCR1
> +     std     r3, STOP_MMCRA(r13)
> +     std     r4, STOP_MMCR1(r13)
> +
> +     mfspr   r3, SPRN_MMCR2
> +     std     r3, STOP_MMCR2(r13)
> +     blr
> +
> +power9_restore_additional_sprs:
> +     ld      r3,_LPCR(r1)
> +     ld      r4, STOP_PID(r13)
> +     mtspr   SPRN_LPCR,r3
> +     mtspr   SPRN_PID, r4
> +
> +     ld      r3, STOP_LDBAR(r13)
> +     ld      r4, STOP_FSCR(r13)
> +     mtspr   SPRN_LDBAR, r3
> +     mtspr   SPRN_FSCR, r4
> +
> +     ld      r3, STOP_HFSCR(r13)
> +     ld      r4, STOP_MMCRA(r13)
> +     mtspr   SPRN_HFSCR, r3
> +     mtspr   SPRN_MMCRA, r4
> +     /* We have already restored PACA_MMCR0 */
> +     ld      r3, STOP_MMCR1(r13)
> +     ld      r4, STOP_MMCR2(r13)
> +     mtspr   SPRN_MMCR1, r3
> +     mtspr   SPRN_MMCR2, r4
>       blr
>  
>  /*
> @@ -790,9 +844,16 @@ no_segments:
>       mtctr   r12
>       bctrl
>  
> +/*
> + * On POWER9, we can come here on wakeup from a cpuidle stop state.
> + * Hence restore the additional SPRs to the saved value.
> + *
> + * On POWER8, we come here only on winkle. Since winkle is used
> + * only in the case of CPU-Hotplug, we don't need to restore
> + * the additional SPRs.
> + */
>  BEGIN_FTR_SECTION
> -     ld      r4,_LPCR(r1)
> -     mtspr   SPRN_LPCR,r4
> +     bl      power9_restore_additional_sprs
>  END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
>  hypervisor_state_restored:
>  

Reply via email to