Skip to content

Commit d405a98

Browse files
shreyasbpmpe
authored andcommitted
powerpc/powernv: Move cpuidle related code from setup.c to new file
This is a cleanup patch; doesn't change any functionality. Moves all cpuidle related code from setup.c to a new file. Signed-off-by: Shreyas B. Prabhu <[email protected]> Reviewed-by: Preeti U Murthy <[email protected]> [mpe: Fix the SMP=n build by including asm/smp.h in idle.c] Signed-off-by: Michael Ellerman <[email protected]>
1 parent e602ffb commit d405a98

File tree

3 files changed

+193
-172
lines changed

3 files changed

+193
-172
lines changed

arch/powerpc/platforms/powernv/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
obj-y += setup.o opal-wrappers.o opal.o opal-async.o
1+
obj-y += setup.o opal-wrappers.o opal.o opal-async.o idle.o
22
obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
33
obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
44
obj-y += opal-msglog.o opal-hmi.o opal-power.o

arch/powerpc/platforms/powernv/idle.c

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/*
2+
* PowerNV cpuidle code
3+
*
4+
* Copyright 2015 IBM Corp.
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU General Public License
8+
* as published by the Free Software Foundation; either version
9+
* 2 of the License, or (at your option) any later version.
10+
*/
11+
12+
#include <linux/types.h>
13+
#include <linux/mm.h>
14+
#include <linux/slab.h>
15+
#include <linux/of.h>
16+
17+
#include <asm/firmware.h>
18+
#include <asm/opal.h>
19+
#include <asm/cputhreads.h>
20+
#include <asm/cpuidle.h>
21+
#include <asm/code-patching.h>
22+
#include <asm/smp.h>
23+
24+
#include "powernv.h"
25+
#include "subcore.h"
26+
27+
static u32 supported_cpuidle_states;
28+
29+
int pnv_save_sprs_for_winkle(void)
30+
{
31+
int cpu;
32+
int rc;
33+
34+
/*
35+
* hid0, hid1, hid4, hid5, hmeer and lpcr values are symmetric accross
36+
* all cpus at boot. Get these reg values of current cpu and use the
37+
* same accross all cpus.
38+
*/
39+
uint64_t lpcr_val = mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1;
40+
uint64_t hid0_val = mfspr(SPRN_HID0);
41+
uint64_t hid1_val = mfspr(SPRN_HID1);
42+
uint64_t hid4_val = mfspr(SPRN_HID4);
43+
uint64_t hid5_val = mfspr(SPRN_HID5);
44+
uint64_t hmeer_val = mfspr(SPRN_HMEER);
45+
46+
for_each_possible_cpu(cpu) {
47+
uint64_t pir = get_hard_smp_processor_id(cpu);
48+
uint64_t hsprg0_val = (uint64_t)&paca[cpu];
49+
50+
/*
51+
* HSPRG0 is used to store the cpu's pointer to paca. Hence last
52+
* 3 bits are guaranteed to be 0. Program slw to restore HSPRG0
53+
* with 63rd bit set, so that when a thread wakes up at 0x100 we
54+
* can use this bit to distinguish between fastsleep and
55+
* deep winkle.
56+
*/
57+
hsprg0_val |= 1;
58+
59+
rc = opal_slw_set_reg(pir, SPRN_HSPRG0, hsprg0_val);
60+
if (rc != 0)
61+
return rc;
62+
63+
rc = opal_slw_set_reg(pir, SPRN_LPCR, lpcr_val);
64+
if (rc != 0)
65+
return rc;
66+
67+
/* HIDs are per core registers */
68+
if (cpu_thread_in_core(cpu) == 0) {
69+
70+
rc = opal_slw_set_reg(pir, SPRN_HMEER, hmeer_val);
71+
if (rc != 0)
72+
return rc;
73+
74+
rc = opal_slw_set_reg(pir, SPRN_HID0, hid0_val);
75+
if (rc != 0)
76+
return rc;
77+
78+
rc = opal_slw_set_reg(pir, SPRN_HID1, hid1_val);
79+
if (rc != 0)
80+
return rc;
81+
82+
rc = opal_slw_set_reg(pir, SPRN_HID4, hid4_val);
83+
if (rc != 0)
84+
return rc;
85+
86+
rc = opal_slw_set_reg(pir, SPRN_HID5, hid5_val);
87+
if (rc != 0)
88+
return rc;
89+
}
90+
}
91+
92+
return 0;
93+
}
94+
95+
static void pnv_alloc_idle_core_states(void)
96+
{
97+
int i, j;
98+
int nr_cores = cpu_nr_cores();
99+
u32 *core_idle_state;
100+
101+
/*
102+
* core_idle_state - First 8 bits track the idle state of each thread
103+
* of the core. The 8th bit is the lock bit. Initially all thread bits
104+
* are set. They are cleared when the thread enters deep idle state
105+
* like sleep and winkle. Initially the lock bit is cleared.
106+
* The lock bit has 2 purposes
107+
* a. While the first thread is restoring core state, it prevents
108+
* other threads in the core from switching to process context.
109+
* b. While the last thread in the core is saving the core state, it
110+
* prevents a different thread from waking up.
111+
*/
112+
for (i = 0; i < nr_cores; i++) {
113+
int first_cpu = i * threads_per_core;
114+
int node = cpu_to_node(first_cpu);
115+
116+
core_idle_state = kmalloc_node(sizeof(u32), GFP_KERNEL, node);
117+
*core_idle_state = PNV_CORE_IDLE_THREAD_BITS;
118+
119+
for (j = 0; j < threads_per_core; j++) {
120+
int cpu = first_cpu + j;
121+
122+
paca[cpu].core_idle_state_ptr = core_idle_state;
123+
paca[cpu].thread_idle_state = PNV_THREAD_RUNNING;
124+
paca[cpu].thread_mask = 1 << j;
125+
}
126+
}
127+
128+
update_subcore_sibling_mask();
129+
130+
if (supported_cpuidle_states & OPAL_PM_WINKLE_ENABLED)
131+
pnv_save_sprs_for_winkle();
132+
}
133+
134+
u32 pnv_get_supported_cpuidle_states(void)
135+
{
136+
return supported_cpuidle_states;
137+
}
138+
EXPORT_SYMBOL_GPL(pnv_get_supported_cpuidle_states);
139+
140+
static int __init pnv_init_idle_states(void)
141+
{
142+
struct device_node *power_mgt;
143+
int dt_idle_states;
144+
u32 *flags;
145+
int i;
146+
147+
supported_cpuidle_states = 0;
148+
149+
if (cpuidle_disable != IDLE_NO_OVERRIDE)
150+
goto out;
151+
152+
if (!firmware_has_feature(FW_FEATURE_OPALv3))
153+
goto out;
154+
155+
power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
156+
if (!power_mgt) {
157+
pr_warn("opal: PowerMgmt Node not found\n");
158+
goto out;
159+
}
160+
dt_idle_states = of_property_count_u32_elems(power_mgt,
161+
"ibm,cpu-idle-state-flags");
162+
if (dt_idle_states < 0) {
163+
pr_warn("cpuidle-powernv: no idle states found in the DT\n");
164+
goto out;
165+
}
166+
167+
flags = kzalloc(sizeof(*flags) * dt_idle_states, GFP_KERNEL);
168+
if (of_property_read_u32_array(power_mgt,
169+
"ibm,cpu-idle-state-flags", flags, dt_idle_states)) {
170+
pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-flags in DT\n");
171+
goto out_free;
172+
}
173+
174+
for (i = 0; i < dt_idle_states; i++)
175+
supported_cpuidle_states |= flags[i];
176+
177+
if (!(supported_cpuidle_states & OPAL_PM_SLEEP_ENABLED_ER1)) {
178+
patch_instruction(
179+
(unsigned int *)pnv_fastsleep_workaround_at_entry,
180+
PPC_INST_NOP);
181+
patch_instruction(
182+
(unsigned int *)pnv_fastsleep_workaround_at_exit,
183+
PPC_INST_NOP);
184+
}
185+
pnv_alloc_idle_core_states();
186+
out_free:
187+
kfree(flags);
188+
out:
189+
return 0;
190+
}
191+
192+
subsys_initcall(pnv_init_idle_states);

arch/powerpc/platforms/powernv/setup.c

Lines changed: 0 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,8 @@
3535
#include <asm/opal.h>
3636
#include <asm/kexec.h>
3737
#include <asm/smp.h>
38-
#include <asm/cputhreads.h>
39-
#include <asm/cpuidle.h>
40-
#include <asm/code-patching.h>
4138

4239
#include "powernv.h"
43-
#include "subcore.h"
4440

4541
static void __init pnv_setup_arch(void)
4642
{
@@ -277,173 +273,6 @@ static void __init pnv_setup_machdep_opal(void)
277273
ppc_md.handle_hmi_exception = opal_handle_hmi_exception;
278274
}
279275

280-
static u32 supported_cpuidle_states;
281-
282-
int pnv_save_sprs_for_winkle(void)
283-
{
284-
int cpu;
285-
int rc;
286-
287-
/*
288-
* hid0, hid1, hid4, hid5, hmeer and lpcr values are symmetric accross
289-
* all cpus at boot. Get these reg values of current cpu and use the
290-
* same accross all cpus.
291-
*/
292-
uint64_t lpcr_val = mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1;
293-
uint64_t hid0_val = mfspr(SPRN_HID0);
294-
uint64_t hid1_val = mfspr(SPRN_HID1);
295-
uint64_t hid4_val = mfspr(SPRN_HID4);
296-
uint64_t hid5_val = mfspr(SPRN_HID5);
297-
uint64_t hmeer_val = mfspr(SPRN_HMEER);
298-
299-
for_each_possible_cpu(cpu) {
300-
uint64_t pir = get_hard_smp_processor_id(cpu);
301-
uint64_t hsprg0_val = (uint64_t)&paca[cpu];
302-
303-
/*
304-
* HSPRG0 is used to store the cpu's pointer to paca. Hence last
305-
* 3 bits are guaranteed to be 0. Program slw to restore HSPRG0
306-
* with 63rd bit set, so that when a thread wakes up at 0x100 we
307-
* can use this bit to distinguish between fastsleep and
308-
* deep winkle.
309-
*/
310-
hsprg0_val |= 1;
311-
312-
rc = opal_slw_set_reg(pir, SPRN_HSPRG0, hsprg0_val);
313-
if (rc != 0)
314-
return rc;
315-
316-
rc = opal_slw_set_reg(pir, SPRN_LPCR, lpcr_val);
317-
if (rc != 0)
318-
return rc;
319-
320-
/* HIDs are per core registers */
321-
if (cpu_thread_in_core(cpu) == 0) {
322-
323-
rc = opal_slw_set_reg(pir, SPRN_HMEER, hmeer_val);
324-
if (rc != 0)
325-
return rc;
326-
327-
rc = opal_slw_set_reg(pir, SPRN_HID0, hid0_val);
328-
if (rc != 0)
329-
return rc;
330-
331-
rc = opal_slw_set_reg(pir, SPRN_HID1, hid1_val);
332-
if (rc != 0)
333-
return rc;
334-
335-
rc = opal_slw_set_reg(pir, SPRN_HID4, hid4_val);
336-
if (rc != 0)
337-
return rc;
338-
339-
rc = opal_slw_set_reg(pir, SPRN_HID5, hid5_val);
340-
if (rc != 0)
341-
return rc;
342-
}
343-
}
344-
345-
return 0;
346-
}
347-
348-
static void pnv_alloc_idle_core_states(void)
349-
{
350-
int i, j;
351-
int nr_cores = cpu_nr_cores();
352-
u32 *core_idle_state;
353-
354-
/*
355-
* core_idle_state - First 8 bits track the idle state of each thread
356-
* of the core. The 8th bit is the lock bit. Initially all thread bits
357-
* are set. They are cleared when the thread enters deep idle state
358-
* like sleep and winkle. Initially the lock bit is cleared.
359-
* The lock bit has 2 purposes
360-
* a. While the first thread is restoring core state, it prevents
361-
* other threads in the core from switching to process context.
362-
* b. While the last thread in the core is saving the core state, it
363-
* prevents a different thread from waking up.
364-
*/
365-
for (i = 0; i < nr_cores; i++) {
366-
int first_cpu = i * threads_per_core;
367-
int node = cpu_to_node(first_cpu);
368-
369-
core_idle_state = kmalloc_node(sizeof(u32), GFP_KERNEL, node);
370-
*core_idle_state = PNV_CORE_IDLE_THREAD_BITS;
371-
372-
for (j = 0; j < threads_per_core; j++) {
373-
int cpu = first_cpu + j;
374-
375-
paca[cpu].core_idle_state_ptr = core_idle_state;
376-
paca[cpu].thread_idle_state = PNV_THREAD_RUNNING;
377-
paca[cpu].thread_mask = 1 << j;
378-
}
379-
}
380-
381-
update_subcore_sibling_mask();
382-
383-
if (supported_cpuidle_states & OPAL_PM_WINKLE_ENABLED)
384-
pnv_save_sprs_for_winkle();
385-
}
386-
387-
u32 pnv_get_supported_cpuidle_states(void)
388-
{
389-
return supported_cpuidle_states;
390-
}
391-
EXPORT_SYMBOL_GPL(pnv_get_supported_cpuidle_states);
392-
393-
static int __init pnv_init_idle_states(void)
394-
{
395-
struct device_node *power_mgt;
396-
int dt_idle_states;
397-
u32 *flags;
398-
int i;
399-
400-
supported_cpuidle_states = 0;
401-
402-
if (cpuidle_disable != IDLE_NO_OVERRIDE)
403-
goto out;
404-
405-
if (!firmware_has_feature(FW_FEATURE_OPALv3))
406-
goto out;
407-
408-
power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
409-
if (!power_mgt) {
410-
pr_warn("opal: PowerMgmt Node not found\n");
411-
goto out;
412-
}
413-
dt_idle_states = of_property_count_u32_elems(power_mgt,
414-
"ibm,cpu-idle-state-flags");
415-
if (dt_idle_states < 0) {
416-
pr_warn("cpuidle-powernv: no idle states found in the DT\n");
417-
goto out;
418-
}
419-
420-
flags = kzalloc(sizeof(*flags) * dt_idle_states, GFP_KERNEL);
421-
if (of_property_read_u32_array(power_mgt,
422-
"ibm,cpu-idle-state-flags", flags, dt_idle_states)) {
423-
pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-flags in DT\n");
424-
goto out_free;
425-
}
426-
427-
for (i = 0; i < dt_idle_states; i++)
428-
supported_cpuidle_states |= flags[i];
429-
430-
if (!(supported_cpuidle_states & OPAL_PM_SLEEP_ENABLED_ER1)) {
431-
patch_instruction(
432-
(unsigned int *)pnv_fastsleep_workaround_at_entry,
433-
PPC_INST_NOP);
434-
patch_instruction(
435-
(unsigned int *)pnv_fastsleep_workaround_at_exit,
436-
PPC_INST_NOP);
437-
}
438-
pnv_alloc_idle_core_states();
439-
out_free:
440-
kfree(flags);
441-
out:
442-
return 0;
443-
}
444-
445-
subsys_initcall(pnv_init_idle_states);
446-
447276
static int __init pnv_probe(void)
448277
{
449278
unsigned long root = of_get_flat_dt_root();

0 commit comments

Comments
 (0)