aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle/cpuidle-powernv.c
diff options
context:
space:
mode:
authorPreeti U Murthy <preeti@linux.vnet.ibm.com>2014-02-25 19:09:20 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-03-04 23:57:08 -0500
commit0888839c5b62c44a55ac9d28acc273ba663c65ea (patch)
tree9365dde8014ff622dee120e8f080320f607753d6 /drivers/cpuidle/cpuidle-powernv.c
parent0d94873011a10cea78d1bc0ba8cfc4203559d534 (diff)
cpuidle/powernv: Parse device tree to setup idle states
Add deep idle states such as nap and fast sleep to the cpuidle state table only if they are discovered from the device tree during cpuidle initialization. Signed-off-by: Preeti U Murthy <preeti@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'drivers/cpuidle/cpuidle-powernv.c')
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c82
1 files changed, 65 insertions, 17 deletions
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index 4fb97cef82fd..fdae1c476e27 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -12,10 +12,17 @@
12#include <linux/cpu.h> 12#include <linux/cpu.h>
13#include <linux/notifier.h> 13#include <linux/notifier.h>
14#include <linux/clockchips.h> 14#include <linux/clockchips.h>
15#include <linux/of.h>
15 16
16#include <asm/machdep.h> 17#include <asm/machdep.h>
17#include <asm/firmware.h> 18#include <asm/firmware.h>
18 19
20/* Flags and constants used in PowerNV platform */
21
22#define MAX_POWERNV_IDLE_STATES 8
23#define IDLE_USE_INST_NAP 0x00010000 /* Use nap instruction */
24#define IDLE_USE_INST_SLEEP 0x00020000 /* Use sleep instruction */
25
19struct cpuidle_driver powernv_idle_driver = { 26struct cpuidle_driver powernv_idle_driver = {
20 .name = "powernv_idle", 27 .name = "powernv_idle",
21 .owner = THIS_MODULE, 28 .owner = THIS_MODULE,
@@ -79,7 +86,7 @@ static int fastsleep_loop(struct cpuidle_device *dev,
79/* 86/*
80 * States for dedicated partition case. 87 * States for dedicated partition case.
81 */ 88 */
82static struct cpuidle_state powernv_states[] = { 89static struct cpuidle_state powernv_states[MAX_POWERNV_IDLE_STATES] = {
83 { /* Snooze */ 90 { /* Snooze */
84 .name = "snooze", 91 .name = "snooze",
85 .desc = "snooze", 92 .desc = "snooze",
@@ -87,20 +94,6 @@ static struct cpuidle_state powernv_states[] = {
87 .exit_latency = 0, 94 .exit_latency = 0,
88 .target_residency = 0, 95 .target_residency = 0,
89 .enter = &snooze_loop }, 96 .enter = &snooze_loop },
90 { /* NAP */
91 .name = "NAP",
92 .desc = "NAP",
93 .flags = CPUIDLE_FLAG_TIME_VALID,
94 .exit_latency = 10,
95 .target_residency = 100,
96 .enter = &nap_loop },
97 { /* Fastsleep */
98 .name = "fastsleep",
99 .desc = "fastsleep",
100 .flags = CPUIDLE_FLAG_TIME_VALID,
101 .exit_latency = 10,
102 .target_residency = 100,
103 .enter = &fastsleep_loop },
104}; 97};
105 98
106static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n, 99static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n,
@@ -161,19 +154,74 @@ static int powernv_cpuidle_driver_init(void)
161 return 0; 154 return 0;
162} 155}
163 156
157static int powernv_add_idle_states(void)
158{
159 struct device_node *power_mgt;
160 struct property *prop;
161 int nr_idle_states = 1; /* Snooze */
162 int dt_idle_states;
163 u32 *flags;
164 int i;
165
166 /* Currently we have snooze statically defined */
167
168 power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
169 if (!power_mgt) {
170 pr_warn("opal: PowerMgmt Node not found\n");
171 return nr_idle_states;
172 }
173
174 prop = of_find_property(power_mgt, "ibm,cpu-idle-state-flags", NULL);
175 if (!prop) {
176 pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-flags\n");
177 return nr_idle_states;
178 }
179
180 dt_idle_states = prop->length / sizeof(u32);
181 flags = (u32 *) prop->value;
182
183 for (i = 0; i < dt_idle_states; i++) {
184
185 if (flags[i] & IDLE_USE_INST_NAP) {
186 /* Add NAP state */
187 strcpy(powernv_states[nr_idle_states].name, "Nap");
188 strcpy(powernv_states[nr_idle_states].desc, "Nap");
189 powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIME_VALID;
190 powernv_states[nr_idle_states].exit_latency = 10;
191 powernv_states[nr_idle_states].target_residency = 100;
192 powernv_states[nr_idle_states].enter = &nap_loop;
193 nr_idle_states++;
194 }
195
196 if (flags[i] & IDLE_USE_INST_SLEEP) {
197 /* Add FASTSLEEP state */
198 strcpy(powernv_states[nr_idle_states].name, "FastSleep");
199 strcpy(powernv_states[nr_idle_states].desc, "FastSleep");
200 powernv_states[nr_idle_states].flags =
201 CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TIMER_STOP;
202 powernv_states[nr_idle_states].exit_latency = 300;
203 powernv_states[nr_idle_states].target_residency = 1000000;
204 powernv_states[nr_idle_states].enter = &fastsleep_loop;
205 nr_idle_states++;
206 }
207 }
208
209 return nr_idle_states;
210}
211
164/* 212/*
165 * powernv_idle_probe() 213 * powernv_idle_probe()
166 * Choose state table for shared versus dedicated partition 214 * Choose state table for shared versus dedicated partition
167 */ 215 */
168static int powernv_idle_probe(void) 216static int powernv_idle_probe(void)
169{ 217{
170
171 if (cpuidle_disable != IDLE_NO_OVERRIDE) 218 if (cpuidle_disable != IDLE_NO_OVERRIDE)
172 return -ENODEV; 219 return -ENODEV;
173 220
174 if (firmware_has_feature(FW_FEATURE_OPALv3)) { 221 if (firmware_has_feature(FW_FEATURE_OPALv3)) {
175 cpuidle_state_table = powernv_states; 222 cpuidle_state_table = powernv_states;
176 max_idle_state = ARRAY_SIZE(powernv_states); 223 /* Device tree can indicate more idle states */
224 max_idle_state = powernv_add_idle_states();
177 } else 225 } else
178 return -ENODEV; 226 return -ENODEV;
179 227