powerpc/64s: Move idle code to powernv C code
Subsystems (2)
Nicholas Piggin
reviewerRFC PATCH v3 1/1 powerpc/64s: Move idle code to powernv C code
Reimplement Book3S idle code to C, in the powernv platform code. Assembly stubs are used to save and restore the stack frame and non-volatile GPRs before going to idle, but these are small and mostly agnostic to microarchitecture implementation details.
The optimisation where EC=ESL=0 idle modes did not have to save GPRs or mtmsrd L=0 is restored, because it's simple to do.
Idle wakeup no longer uses the ->cpu_restore call to reinit SPRs, but saves and restores them all explicitly. This can easily be extended to tracking the set of system-wide SPRs that do not have to be saved each time.
Moving the HMI, SPR, OPAL, locking, etc. to C is the only real way this stuff will cope with non-trivial new CPU implementation details, firmware changes, etc., without becoming unmaintainable.
Since RFC v1:
- Now tested and working with POWER9 hash and radix.
- KVM support added. This took a bit of work to untangle and might still have some issues, but POWER9 seems to work including hash on radix with dependent threads mode.
- This snowballed a bit because of KVM and other details making it not feasible to leave POWER7/8 code alone. That's only half done at the moment.
- So far this trades about 800 lines of asm for 500 of C. With POWER7/8 support done it might be another hundred or so lines of C.
Since RFC v2:
- Fixed deep state SLB reloading
- Now tested and working with POWER8.
- Accounted for most feedback.
Thanks,
Nick
--- include/asm/book3s/64/mmu-hash.h | 1 include/asm/cpuidle.h | 21 include/asm/paca.h | 40 - include/asm/processor.h | 9 include/asm/reg.h | 7 kernel/asm-offsets.c | 18 kernel/dt_cpu_ftrs.c | 21 kernel/exceptions-64s.S | 17 kernel/idle_book3s.S | 998 +++------------------------------------ kernel/setup-common.c | 4 kvm/book3s_hv_rmhandlers.S | 94 ++- mm/slb.c | 15 platforms/powernv/idle.c | 839 ++++++++++++++++++++++++++------ platforms/powernv/subcore.c | 2 xmon/xmon.c | 25 15 files changed, 902 insertions(+), 1209 deletions(-)
arch/powerpc/include/asm/book3s/64/mmu-hash.h +1 -0
@@ -487,6 +487,7 @@ extern void hpte_init_native(void);extern void slb_initialize (void );extern void slb_flush_and_rebolt (void ); +extern void slb_shadow_reload (void );extern void slb_vmalloc_update (void );extern void slb_set_size (u16 size);
arch/powerpc/include/asm/cpuidle.h +3 -18
@@ -27,10 +27,11 @@* the THREAD_WINKLE_BITS are set, which indicate which threads have not * yet woken from the winkle state. */ -#define PNV_CORE_IDLE_LOCK_BIT 0x10000000 +#define NR_PNV_CORE_IDLE_LOCK_BIT 28 +#define PNV_CORE_IDLE_LOCK_BIT (1ULL << NR_PNV_CORE_IDLE_LOCK_BIT) +#define PNV_CORE_IDLE_WINKLE_COUNT_SHIFT 16#define PNV_CORE_IDLE_WINKLE_COUNT 0x00010000 -#define PNV_CORE_IDLE_WINKLE_COUNT_ALL_BIT 0x00080000#define PNV_CORE_IDLE_WINKLE_COUNT_BITS 0x000F0000#define PNV_CORE_IDLE_THREAD_WINKLE_BITS_SHIFT 8#define PNV_CORE_IDLE_THREAD_WINKLE_BITS 0x0000FF00
@@ -68,22 +69,6 @@#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[]; - -extern u64 pnv_first_deep_stop_state; -unsigned long pnv_cpu_offline (unsigned int cpu);int validate_psscr_val_mask (u64 *psscr_val,u64 *psscr_mask,u32 flags);static inline void report_invalid_psscr_val (u64 psscr_val,int err)
arch/powerpc/include/asm/paca.h +23 -17
@@ -168,7 +168,6 @@ struct paca_struct {u8 irq_happened;/* irq happened while soft-disabled */ u8 io_sync;/* writel() needs spin_unlock sync */ u8 irq_work_pending;/* IRQ_WORK interrupt while soft-disable */ -u8 nap_state_lost;/* NV GPR values lost in power7_idle */ #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE u8 pmcregs_in_use;/* pseries puts this in lppaca */ #endif
@@ -178,23 +177,30 @@ struct paca_struct {#endif #ifdef CONFIG_PPC_POWERNV -/* Per-core mask tracking idle threads and a lock bit-[L][TTTTTTTT] */ -u32 *core_idle_state_ptr; -u8 thread_idle_state;/* PNV_THREAD_RUNNING/NAP/SLEEP */ -/* Mask to indicate thread id in core */ -u8 thread_mask; -/* Mask to denote subcore sibling threads */ -u8 subcore_sibling_mask; -/* Flag to request this thread not to stop */ -atomic_t dont_stop; -/* The PSSCR value that the kernel requested before going to stop */ -u64 requested_psscr; +/* PowerNV idle fields */ +/* PNV_CORE_IDLE_* bits, all siblings work on thread 0 paca */ +unsigned long idle_state; +union { +/* P7/P8 specific fields */ +struct { +/* PNV_THREAD_RUNNING/NAP/SLEEP */ +u8 thread_idle_state; +/* Mask to indicate thread id in core */ +u8 thread_mask; +/* Mask to denote subcore sibling threads */ +u8 subcore_sibling_mask; + }; -/* -* Save area for additional SPRs that need to be -* saved/restored during cpuidle stop. -*/ -struct stop_sprs stop_sprs; +/* P9 specific fields */ +struct { +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE +/* The PSSCR value that the kernel requested before going to stop */ +u64 requested_psscr; +/* Flag to request this thread not to stop */ +atomic_t dont_stop; +#endif + }; + };#endif #ifdef CONFIG_PPC_BOOK3S_64
arch/powerpc/include/asm/processor.h +6 -3
@@ -507,14 +507,17 @@ static inline unsigned long get_clean_sp(unsigned long sp, int is_32) }#endif +/* asm stubs */ +extern unsigned long isa3_idle_stop_noloss (unsigned long psscr_val); +extern unsigned long isa3_idle_stop_mayloss (unsigned long psscr_val); +extern unsigned long isa206_idle_insn_mayloss (unsigned long type); +extern unsigned long cpuidle_disable;enum idle_boot_override {IDLE_NO_OVERRIDE =0 ,IDLE_POWERSAVE_OFF };extern int powersave_nap;/* set if nap mode can be used in idle loop */ -extern unsigned long power7_idle_insn (unsigned long type);/* PNV_THREAD_NAP/etc*/ +extern void power7_idle_type (unsigned long type); -extern unsigned long power9_idle_stop (unsigned long psscr_val); -extern unsigned long power9_offline_stop (unsigned long psscr_val);extern void power9_idle_type (unsigned long stop_psscr_val,unsigned long stop_psscr_mask);
arch/powerpc/include/asm/reg.h +3 -4
@@ -753,10 +753,9 @@#define SRR1_WAKERESET 0x00100000/* System reset */ #define SRR1_WAKEHDBELL 0x000c0000/* Hypervisor doorbell on P8 */ #define SRR1_WAKESTATE 0x00030000/* Powersave exit mask [46:47] */ -#define SRR1_WS_DEEPEST 0x00030000/* Some resources not maintained, -* may not be recoverable */ -#define SRR1_WS_DEEPER 0x00020000/* Some resources not maintained */ -#define SRR1_WS_DEEP 0x00010000/* All resources maintained */ +#define SRR1_WS_HVLOSS 0x00030000/* HV resources not maintained */ +#define SRR1_WS_GPRLOSS 0x00020000/* GPRs not maintained */ +#define SRR1_WS_NOLOSS 0x00010000/* All resources maintained */ #define SRR1_PROGTM 0x00200000/* TM Bad Thing */ #define SRR1_PROGFPE 0x00100000/* Floating Point Enabled */ #define SRR1_PROGILL 0x00080000/* Illegal instruction */
arch/powerpc/kernel/asm-offsets.c +0 -18
@@ -256,7 +256,6 @@ int main(void)OFFSET (ACCOUNT_USER_TIME , paca_struct, accounting.utime);OFFSET (ACCOUNT_SYSTEM_TIME , paca_struct, accounting.stime);OFFSET (PACA_TRAP_SAVE , paca_struct, trap_save); -OFFSET (PACA_NAPSTATELOST , paca_struct, nap_state_lost);OFFSET (PACA_SPRG_VDSO , paca_struct, sprg_vdso);#else /* CONFIG_PPC64 */ #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
@@ -761,23 +760,6 @@ int main(void)OFFSET (VCPU_TIMING_LAST_ENTER_TBL , kvm_vcpu, arch.timing_last_enter.tv32.tbl);#endif -#ifdef CONFIG_PPC_POWERNV -OFFSET (PACA_CORE_IDLE_STATE_PTR , paca_struct, core_idle_state_ptr); -OFFSET (PACA_THREAD_IDLE_STATE , paca_struct, thread_idle_state); -OFFSET (PACA_THREAD_MASK , paca_struct, thread_mask); -OFFSET (PACA_SUBCORE_SIBLING_MASK , paca_struct, subcore_sibling_mask); -OFFSET (PACA_REQ_PSSCR , paca_struct, requested_psscr); -OFFSET (PACA_DONT_STOP , paca_struct, dont_stop); -#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 );DEFINE (PPC_DBELL_MSGTYPE ,PPC_DBELL_MSGTYPE );
arch/powerpc/kernel/dt_cpu_ftrs.c +1 -20
@@ -71,7 +71,6 @@ static int hv_mode;static struct {u64 lpcr; -u64 lpcr_clear;u64 hfscr;u64 fscr; } system_registers;
@@ -80,24 +79,7 @@ static void (*init_pmu_registers)(void);static void __restore_cpu_cpufeatures (void ) { -u64 lpcr; - -/* -* LPCR is restored by the power on engine already. It can be changed -* after early init e.g., by radix enable, and we have no unified API -* for saving and restoring such SPRs. -* -* This ->restore hook should really be removed from idle and register -* restore moved directly into the idle restore code, because this code -* doesn't know how idle is implemented or what it needs restored here. -* -* The best we can do to accommodate secondary boot and idle restore -* for now is "or" LPCR with existing. -*/ - lpcr =mfspr (SPRN_LPCR ); - lpcr |= system_registers.lpcr; - lpcr &= ~system_registers.lpcr_clear; -mtspr (SPRN_LPCR , lpcr); +mtspr (SPRN_LPCR , system_registers.lpcr);if (hv_mode) {mtspr (SPRN_LPID ,0 );mtspr (SPRN_HFSCR , system_registers.hfscr);
@@ -318,7 +300,6 @@ static int __init feat_enable_mmu_hash_v3(struct dt_cpu_feature *f) {u64 lpcr; - system_registers.lpcr_clear |= (LPCR_ISL |LPCR_UPRT |LPCR_HR ); lpcr =mfspr (SPRN_LPCR ); lpcr &= ~(LPCR_ISL |LPCR_UPRT |LPCR_HR );mtspr (SPRN_LPCR , lpcr);
arch/powerpc/kernel/exceptions-64s.S +9 -8
@@ -135,8 +135,9 @@ TRAMP_KVM(PACA_EXNMI, 0x100) #ifdef CONFIG_PPC_P7_NAP EXC_COMMON_BEGIN(system_reset_idle_common) - mfspr r12,SPRN_SRR1 - b pnv_powersave_wakeup + mfspr r3,SPRN_SRR1 + bltlr cr3 /* no state loss, return to idle caller */ + b idle_return_gpr_loss #endif /*
@@ -415,17 +416,17 @@ EXC_COMMON_BEGIN(machine_check_idle_common) * Then decrement MCE nesting after finishing with the stack. */ ld r3,_MSR(r1) + ld r4,_LINK(r1) lhz r11,PACA_IN_MCE(r13) subi r11,r11,1 sth r11,PACA_IN_MCE(r13) - /* Turn off the RI bit because SRR1 is used by idle wakeup code. */ - /* Recoverability could be improved by reducing the use of SRR1. */ - li r11,0 - mtmsrd r11,1 - - b pnv_powersave_wakeup_mce + mtlr r4 + rlwinm r10,r3,47-31,30,31 + cmpwi cr3,r10,2 + bltlr cr3 /* no state loss, return to idle caller */ + b idle_return_gpr_loss #endif /* * Handle machine check early in real mode. We come here with
arch/powerpc/kernel/idle_book3s.S +90 -908
1,037 lines not on this page · raw message
arch/powerpc/kernel/setup-common.c +2 -2
@@ -401,8 +401,8 @@ void __init check_for_initrd(void)#ifdef CONFIG_SMP -int threads_per_core, threads_per_subcore, threads_shift; -cpumask_t threads_core_mask; +int threads_per_core, threads_per_subcore, threads_shift__read_mostly ; +cpumask_t threads_core_mask__read_mostly ;EXPORT_SYMBOL_GPL (threads_per_core);EXPORT_SYMBOL_GPL (threads_per_subcore);EXPORT_SYMBOL_GPL (threads_shift);
arch/powerpc/kvm/book3s_hv_rmhandlers.S +56 -38
169 lines not on this page · raw message
arch/powerpc/mm/slb.c +15 -0
@@ -90,6 +90,21 @@ static inline void create_shadowed_slbe(unsigned long ea, int ssize, : "memory" ); } +void slb_shadow_reload (void ) +{ +struct slb_shadow *p =get_slb_shadow (); +enum slb_index index; + +for (index =0 ; index <SLB_NUM_BOLTED ; index++) { +if (be64_to_cpu (p->save_area[index].esid) &SLB_ESID_V ) { + asmvolatile ("slbmte %0,%1" : + :"r" (be64_to_cpu (p->save_area[index].vsid)), +"r" (be64_to_cpu (p->save_area[index].esid))); + } + } +isync (); +} +static void __slb_flush_and_rebolt (void ) {/* If you change this make sure you change SLB_NUM_BOLTED
arch/powerpc/platforms/powernv/idle.c +681 -158
1,019 lines not on this page · raw message
arch/powerpc/platforms/powernv/subcore.c +1 -1
@@ -183,7 +183,7 @@ static void unsplit_core(void) cpu =smp_processor_id ();if (cpu_thread_in_core (cpu) !=0 ) {while (mfspr (SPRN_HID0 ) & mask) -power7_idle_insn (PNV_THREAD_NAP ); +power7_idle_type (PNV_THREAD_NAP );per_cpu (split_state, cpu).step =SYNC_STEP_UNSPLIT ;return ;
arch/powerpc/xmon/xmon.c +11 -14
@@ -2417,7 +2417,6 @@ static void dump_one_paca(int cpu)DUMP (p, irq_happened,"%#-*x" );DUMP (p, io_sync,"%#-*x" );DUMP (p, irq_work_pending,"%#-*x" ); -DUMP (p, nap_state_lost,"%#-*x" );DUMP (p, sprg_vdso,"%#-*llx" );#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
@@ -2425,19 +2424,17 @@ static void dump_one_paca(int cpu)#endif #ifdef CONFIG_PPC_POWERNV -DUMP (p, core_idle_state_ptr,"%-*px" ); -DUMP (p, thread_idle_state,"%#-*x" ); -DUMP (p, thread_mask,"%#-*x" ); -DUMP (p, subcore_sibling_mask,"%#-*x" ); -DUMP (p, requested_psscr,"%#-*llx" ); -DUMP (p, stop_sprs.pid,"%#-*llx" ); -DUMP (p, stop_sprs.ldbar,"%#-*llx" ); -DUMP (p, stop_sprs.fscr,"%#-*llx" ); -DUMP (p, stop_sprs.hfscr,"%#-*llx" ); -DUMP (p, stop_sprs.mmcr1,"%#-*llx" ); -DUMP (p, stop_sprs.mmcr2,"%#-*llx" ); -DUMP (p, stop_sprs.mmcra,"%#-*llx" ); -DUMP (p, dont_stop.counter,"%#-*x" ); +DUMP (p, idle_state,"%#-*lx" ); +if (!cpu_has_feature (CPU_FTR_ARCH_300 )) { +DUMP (p, thread_idle_state,"%#-*x" ); +DUMP (p, thread_mask,"%#-*x" ); +DUMP (p, subcore_sibling_mask,"%#-*x" ); + }else { +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE +DUMP (p, requested_psscr,"%#-*llx" ); +DUMP (p, dont_stop.counter,"%#-*x" ); +#endif + }#endif DUMP (p, accounting.utime,"%#-*lx" );