Skip to content

Commit 77b54e9

Browse files
shreyasbpmpe
authored andcommitted
powernv/powerpc: Add winkle support for offline cpus
Winkle is a deep idle state supported in power8 chips. A core enters winkle when all the threads of the core enter winkle. In this state power supply to the entire chiplet i.e core, private L2 and private L3 is turned off. As a result it gives higher powersavings compared to sleep. But entering winkle results in a total hypervisor state loss. Hence the hypervisor context has to be preserved before entering winkle and restored upon wake up. Power-on Reset Engine (PORE) is a dedicated engine which is responsible for powering on the chiplet during wake up. It can be programmed to restore the register contests of a few specific registers. This patch uses PORE to restore register state wherever possible and uses stack to save and restore rest of the necessary registers. With hypervisor state restore things fall under three categories- per-core state, per-subcore state and per-thread state. To manage this, extend the infrastructure introduced for sleep. Mainly we add a paca variable subcore_sibling_mask. Using this and the core_idle_state we can distingush first thread in core and subcore. Signed-off-by: Shreyas B. Prabhu <shreyas@linux.vnet.ibm.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
1 parent 7cba160 commit 77b54e9

File tree

13 files changed

+281
-12
lines changed

13 files changed

+281
-12
lines changed

arch/powerpc/include/asm/opal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ struct opal_sg_list {
161161
#define OPAL_PCI_EEH_FREEZE_SET 97
162162
#define OPAL_HANDLE_HMI 98
163163
#define OPAL_CONFIG_CPU_IDLE_STATE 99
164+
#define OPAL_SLW_SET_REG 100
164165
#define OPAL_REGISTER_DUMP_REGION 101
165166
#define OPAL_UNREGISTER_DUMP_REGION 102
166167
#define OPAL_WRITE_TPO 103
@@ -176,6 +177,7 @@ struct opal_sg_list {
176177
*/
177178
#define OPAL_PM_NAP_ENABLED 0x00010000
178179
#define OPAL_PM_SLEEP_ENABLED 0x00020000
180+
#define OPAL_PM_WINKLE_ENABLED 0x00040000
179181
#define OPAL_PM_SLEEP_ENABLED_ER1 0x00080000
180182

181183
#ifndef __ASSEMBLY__
@@ -913,6 +915,7 @@ int64_t opal_sensor_read(uint32_t sensor_hndl, int token, __be32 *sensor_data);
913915
int64_t opal_handle_hmi(void);
914916
int64_t opal_register_dump_region(uint32_t id, uint64_t start, uint64_t end);
915917
int64_t opal_unregister_dump_region(uint32_t id);
918+
int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val);
916919
int64_t opal_pci_set_phb_cxl_mode(uint64_t phb_id, uint64_t mode, uint64_t pe_number);
917920
int64_t opal_ipmi_send(uint64_t interface, struct opal_ipmi_msg *msg,
918921
uint64_t msg_len);

arch/powerpc/include/asm/paca.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ struct paca_struct {
158158
u8 thread_idle_state; /* PNV_THREAD_RUNNING/NAP/SLEEP */
159159
/* Mask to indicate thread id in core */
160160
u8 thread_mask;
161+
/* Mask to denote subcore sibling threads */
162+
u8 subcore_sibling_mask;
161163
#endif
162164

163165
#ifdef CONFIG_PPC_BOOK3S_64

arch/powerpc/include/asm/ppc-opcode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@
194194

195195
#define PPC_INST_NAP 0x4c000364
196196
#define PPC_INST_SLEEP 0x4c0003a4
197+
#define PPC_INST_WINKLE 0x4c0003e4
197198

198199
/* A2 specific instructions */
199200
#define PPC_INST_ERATWE 0x7c0001a6
@@ -374,6 +375,7 @@
374375

375376
#define PPC_NAP stringify_in_c(.long PPC_INST_NAP)
376377
#define PPC_SLEEP stringify_in_c(.long PPC_INST_SLEEP)
378+
#define PPC_WINKLE stringify_in_c(.long PPC_INST_WINKLE)
377379

378380
/* BHRB instructions */
379381
#define PPC_CLRBHRB stringify_in_c(.long PPC_INST_CLRBHRB)

arch/powerpc/include/asm/processor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
453453
extern int powersave_nap; /* set if nap mode can be used in idle loop */
454454
extern unsigned long power7_nap(int check_irq);
455455
extern unsigned long power7_sleep(void);
456+
extern unsigned long power7_winkle(void);
456457
extern void flush_instruction_cache(void);
457458
extern void hard_reset_now(void);
458459
extern void poweroff_now(void);

arch/powerpc/include/asm/reg.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@
373373
#define SPRN_DBAT7L 0x23F /* Data BAT 7 Lower Register */
374374
#define SPRN_DBAT7U 0x23E /* Data BAT 7 Upper Register */
375375
#define SPRN_PPR 0x380 /* SMT Thread status Register */
376+
#define SPRN_TSCR 0x399 /* Thread Switch Control Register */
376377

377378
#define SPRN_DEC 0x016 /* Decrement Register */
378379
#define SPRN_DER 0x095 /* Debug Enable Regsiter */
@@ -730,6 +731,7 @@
730731
#define SPRN_BESCR 806 /* Branch event status and control register */
731732
#define BESCR_GE 0x8000000000000000ULL /* Global Enable */
732733
#define SPRN_WORT 895 /* Workload optimization register - thread */
734+
#define SPRN_WORC 863 /* Workload optimization register - core */
733735

734736
#define SPRN_PMC1 787
735737
#define SPRN_PMC2 788

arch/powerpc/kernel/asm-offsets.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,8 @@ int main(void)
733733
offsetof(struct paca_struct, thread_idle_state));
734734
DEFINE(PACA_THREAD_MASK,
735735
offsetof(struct paca_struct, thread_mask));
736+
DEFINE(PACA_SUBCORE_SIBLING_MASK,
737+
offsetof(struct paca_struct, subcore_sibling_mask));
736738
#endif
737739

738740
return 0;

arch/powerpc/kernel/exceptions-64s.S

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,17 +102,24 @@ system_reset_pSeries:
102102
#ifdef CONFIG_PPC_P7_NAP
103103
BEGIN_FTR_SECTION
104104
/* Running native on arch 2.06 or later, check if we are
105-
* waking up from nap. We only handle no state loss and
106-
* supervisor state loss. We do -not- handle hypervisor
107-
* state loss at this time.
105+
* waking up from nap/sleep/winkle.
108106
*/
109107
mfspr r13,SPRN_SRR1
110108
rlwinm. r13,r13,47-31,30,31
111109
beq 9f
112110

113111
cmpwi cr3,r13,2
114112

113+
/*
114+
* Check if last bit of HSPGR0 is set. This indicates whether we are
115+
* waking up from winkle.
116+
*/
115117
GET_PACA(r13)
118+
clrldi r5,r13,63
119+
clrrdi r13,r13,1
120+
cmpwi cr4,r5,1
121+
mtspr SPRN_HSPRG0,r13
122+
116123
lbz r0,PACA_THREAD_IDLE_STATE(r13)
117124
cmpwi cr2,r0,PNV_THREAD_NAP
118125
bgt cr2,8f /* Either sleep or Winkle */

arch/powerpc/kernel/idle_power7.S

Lines changed: 138 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,24 @@
1919
#include <asm/kvm_book3s_asm.h>
2020
#include <asm/opal.h>
2121
#include <asm/cpuidle.h>
22+
#include <asm/mmu-hash64.h>
2223

2324
#undef DEBUG
2425

26+
/*
27+
* Use unused space in the interrupt stack to save and restore
28+
* registers for winkle support.
29+
*/
30+
#define _SDR1 GPR3
31+
#define _RPR GPR4
32+
#define _SPURR GPR5
33+
#define _PURR GPR6
34+
#define _TSCR GPR7
35+
#define _DSCR GPR8
36+
#define _AMOR GPR9
37+
#define _WORT GPR10
38+
#define _WORC GPR11
39+
2540
/* Idle state entry routines */
2641

2742
#define IDLE_STATE_ENTER_SEQ(IDLE_INST) \
@@ -124,8 +139,8 @@ power7_enter_nap_mode:
124139
stb r4,HSTATE_HWTHREAD_STATE(r13)
125140
#endif
126141
stb r3,PACA_THREAD_IDLE_STATE(r13)
127-
cmpwi cr1,r3,PNV_THREAD_SLEEP
128-
bge cr1,2f
142+
cmpwi cr3,r3,PNV_THREAD_SLEEP
143+
bge cr3,2f
129144
IDLE_STATE_ENTER_SEQ(PPC_NAP)
130145
/* No return */
131146
2:
@@ -154,7 +169,8 @@ pnv_fastsleep_workaround_at_entry:
154169
bne- lwarx_loop1
155170
isync
156171

157-
common_enter: /* common code for all the threads entering sleep */
172+
common_enter: /* common code for all the threads entering sleep or winkle */
173+
bgt cr3,enter_winkle
158174
IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
159175

160176
fastsleep_workaround_at_entry:
@@ -175,6 +191,30 @@ fastsleep_workaround_at_entry:
175191
stw r0,0(r14)
176192
b common_enter
177193

194+
enter_winkle:
195+
/*
196+
* Note all register i.e per-core, per-subcore or per-thread is saved
197+
* here since any thread in the core might wake up first
198+
*/
199+
mfspr r3,SPRN_SDR1
200+
std r3,_SDR1(r1)
201+
mfspr r3,SPRN_RPR
202+
std r3,_RPR(r1)
203+
mfspr r3,SPRN_SPURR
204+
std r3,_SPURR(r1)
205+
mfspr r3,SPRN_PURR
206+
std r3,_PURR(r1)
207+
mfspr r3,SPRN_TSCR
208+
std r3,_TSCR(r1)
209+
mfspr r3,SPRN_DSCR
210+
std r3,_DSCR(r1)
211+
mfspr r3,SPRN_AMOR
212+
std r3,_AMOR(r1)
213+
mfspr r3,SPRN_WORT
214+
std r3,_WORT(r1)
215+
mfspr r3,SPRN_WORC
216+
std r3,_WORC(r1)
217+
IDLE_STATE_ENTER_SEQ(PPC_WINKLE)
178218

179219
_GLOBAL(power7_idle)
180220
/* Now check if user or arch enabled NAP mode */
@@ -197,6 +237,12 @@ _GLOBAL(power7_sleep)
197237
b power7_powersave_common
198238
/* No return */
199239

240+
_GLOBAL(power7_winkle)
241+
li r3,3
242+
li r4,1
243+
b power7_powersave_common
244+
/* No return */
245+
200246
#define CHECK_HMI_INTERRUPT \
201247
mfspr r0,SPRN_SRR1; \
202248
BEGIN_FTR_SECTION_NESTED(66); \
@@ -250,11 +296,23 @@ lwarx_loop2:
250296
bne core_idle_lock_held
251297

252298
cmpwi cr2,r15,0
299+
lbz r4,PACA_SUBCORE_SIBLING_MASK(r13)
300+
and r4,r4,r15
301+
cmpwi cr1,r4,0 /* Check if first in subcore */
302+
303+
/*
304+
* At this stage
305+
* cr1 - 0b0100 if first thread to wakeup in subcore
306+
* cr2 - 0b0100 if first thread to wakeup in core
307+
* cr3- 0b0010 if waking up from sleep or winkle
308+
* cr4 - 0b0100 if waking up from winkle
309+
*/
310+
253311
or r15,r15,r7 /* Set thread bit */
254312

255-
beq cr2,first_thread
313+
beq cr1,first_thread_in_subcore
256314

257-
/* Not first thread in core to wake up */
315+
/* Not first thread in subcore to wake up */
258316
stwcx. r15,0,r14
259317
bne- lwarx_loop2
260318
isync
@@ -269,13 +327,36 @@ core_idle_lock_loop:
269327
HMT_MEDIUM
270328
b lwarx_loop2
271329

272-
first_thread:
273-
/* First thread in core to wakeup */
330+
first_thread_in_subcore:
331+
/* First thread in subcore to wakeup */
274332
ori r15,r15,PNV_CORE_IDLE_LOCK_BIT
275333
stwcx. r15,0,r14
276334
bne- lwarx_loop2
277335
isync
278336

337+
/*
338+
* If waking up from sleep, subcore state is not lost. Hence
339+
* skip subcore state restore
340+
*/
341+
bne cr4,subcore_state_restored
342+
343+
/* Restore per-subcore state */
344+
ld r4,_SDR1(r1)
345+
mtspr SPRN_SDR1,r4
346+
ld r4,_RPR(r1)
347+
mtspr SPRN_RPR,r4
348+
ld r4,_AMOR(r1)
349+
mtspr SPRN_AMOR,r4
350+
351+
subcore_state_restored:
352+
/*
353+
* Check if the thread is also the first thread in the core. If not,
354+
* skip to clear_lock.
355+
*/
356+
bne cr2,clear_lock
357+
358+
first_thread_in_core:
359+
279360
/*
280361
* First thread in the core waking up from fastsleep. It needs to
281362
* call the fastsleep workaround code if the platform requires it.
@@ -296,12 +377,62 @@ timebase_resync:
296377
bl opal_call_realmode;
297378
/* TODO: Check r3 for failure */
298379

380+
/*
381+
* If waking up from sleep, per core state is not lost, skip to
382+
* clear_lock.
383+
*/
384+
bne cr4,clear_lock
385+
386+
/* Restore per core state */
387+
ld r4,_TSCR(r1)
388+
mtspr SPRN_TSCR,r4
389+
ld r4,_WORC(r1)
390+
mtspr SPRN_WORC,r4
391+
299392
clear_lock:
300393
andi. r15,r15,PNV_CORE_IDLE_THREAD_BITS
301394
lwsync
302395
stw r15,0(r14)
303396

304397
common_exit:
398+
/*
399+
* Common to all threads.
400+
*
401+
* If waking up from sleep, hypervisor state is not lost. Hence
402+
* skip hypervisor state restore.
403+
*/
404+
bne cr4,hypervisor_state_restored
405+
406+
/* Waking up from winkle */
407+
408+
/* Restore per thread state */
409+
bl __restore_cpu_power8
410+
411+
/* Restore SLB from PACA */
412+
ld r8,PACA_SLBSHADOWPTR(r13)
413+
414+
.rept SLB_NUM_BOLTED
415+
li r3, SLBSHADOW_SAVEAREA
416+
LDX_BE r5, r8, r3
417+
addi r3, r3, 8
418+
LDX_BE r6, r8, r3
419+
andis. r7,r5,SLB_ESID_V@h
420+
beq 1f
421+
slbmte r6,r5
422+
1: addi r8,r8,16
423+
.endr
424+
425+
ld r4,_SPURR(r1)
426+
mtspr SPRN_SPURR,r4
427+
ld r4,_PURR(r1)
428+
mtspr SPRN_PURR,r4
429+
ld r4,_DSCR(r1)
430+
mtspr SPRN_DSCR,r4
431+
ld r4,_WORT(r1)
432+
mtspr SPRN_WORT,r4
433+
434+
hypervisor_state_restored:
435+
305436
li r5,PNV_THREAD_RUNNING
306437
stb r5,PACA_THREAD_IDLE_STATE(r13)
307438

arch/powerpc/platforms/powernv/opal-wrappers.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ OPAL_CALL(opal_sensor_read, OPAL_SENSOR_READ);
284284
OPAL_CALL(opal_get_param, OPAL_GET_PARAM);
285285
OPAL_CALL(opal_set_param, OPAL_SET_PARAM);
286286
OPAL_CALL(opal_handle_hmi, OPAL_HANDLE_HMI);
287+
OPAL_CALL(opal_slw_set_reg, OPAL_SLW_SET_REG);
287288
OPAL_CALL(opal_register_dump_region, OPAL_REGISTER_DUMP_REGION);
288289
OPAL_CALL(opal_unregister_dump_region, OPAL_UNREGISTER_DUMP_REGION);
289290
OPAL_CALL(opal_pci_set_phb_cxl_mode, OPAL_PCI_SET_PHB_CXL_MODE);

0 commit comments

Comments
 (0)