aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorPreeti U Murthy <preeti@linux.vnet.ibm.com>2015-02-18 00:34:17 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-02-18 00:34:17 -0500
commit92c83ff5b42b109c94fdeee53cb31f674f776d75 (patch)
treee8ca5ef30cc1bd687496139d9905452798dde8c8 /drivers/cpuidle
parent5177a94aea6fbffc897aaee29c7cde57f951b541 (diff)
cpuidle: powernv: Read target_residency value of idle states from DT if available
The device tree now exposes the residency values for different idle states. Read these values instead of calculating residency from the latency values. The values exposed in the DT are validated for optimal power efficiency. However to maintain compatibility with the older firmware code which does not expose residency values, use default values as a fallback mechanism. While at it, use better APIs to parse the powermgmt device tree node. Signed-off-by: Preeti U Murthy <preeti@linux.vnet.ibm.com> Acked-by: Stewart Smith <stewart@linux.vnet.ibm.com> Acked-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c69
1 files changed, 40 insertions, 29 deletions
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index aedec0957934..30d42298a69f 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -13,6 +13,7 @@
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#include <linux/of.h>
16#include <linux/slab.h>
16 17
17#include <asm/machdep.h> 18#include <asm/machdep.h>
18#include <asm/firmware.h> 19#include <asm/firmware.h>
@@ -159,69 +160,79 @@ static int powernv_add_idle_states(void)
159 int nr_idle_states = 1; /* Snooze */ 160 int nr_idle_states = 1; /* Snooze */
160 int dt_idle_states; 161 int dt_idle_states;
161 const __be32 *idle_state_flags; 162 const __be32 *idle_state_flags;
162 const __be32 *idle_state_latency; 163 u32 len_flags, flags;
163 u32 len_flags, flags, latency_ns; 164 u32 *latency_ns, *residency_ns;
164 int i; 165 int i, rc;
165 166
166 /* Currently we have snooze statically defined */ 167 /* Currently we have snooze statically defined */
167 168
168 power_mgt = of_find_node_by_path("/ibm,opal/power-mgt"); 169 power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
169 if (!power_mgt) { 170 if (!power_mgt) {
170 pr_warn("opal: PowerMgmt Node not found\n"); 171 pr_warn("opal: PowerMgmt Node not found\n");
171 return nr_idle_states; 172 goto out;
172 } 173 }
173 174
174 idle_state_flags = of_get_property(power_mgt, "ibm,cpu-idle-state-flags", &len_flags); 175 idle_state_flags = of_get_property(power_mgt,
176 "ibm,cpu-idle-state-flags", &len_flags);
175 if (!idle_state_flags) { 177 if (!idle_state_flags) {
176 pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-flags\n"); 178 pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-flags in DT\n");
177 return nr_idle_states; 179 goto out;
178 } 180 }
179 181
180 idle_state_latency = of_get_property(power_mgt, 182 dt_idle_states = len_flags / sizeof(u32);
181 "ibm,cpu-idle-state-latencies-ns", NULL); 183
182 if (!idle_state_latency) { 184 latency_ns = kzalloc(sizeof(*latency_ns) * dt_idle_states, GFP_KERNEL);
183 pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-latencies-ns\n"); 185 rc = of_property_read_u32_array(power_mgt,
184 return nr_idle_states; 186 "ibm,cpu-idle-state-latencies-ns", latency_ns, dt_idle_states);
187 if (rc) {
188 pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT\n");
189 goto out_free_latency;
185 } 190 }
186 191
187 dt_idle_states = len_flags / sizeof(u32); 192 residency_ns = kzalloc(sizeof(*residency_ns) * dt_idle_states, GFP_KERNEL);
193 rc = of_property_read_u32_array(power_mgt,
194 "ibm,cpu-idle-state-residency-ns", residency_ns, dt_idle_states);
188 195
189 for (i = 0; i < dt_idle_states; i++) { 196 for (i = 0; i < dt_idle_states; i++) {
190 197
191 flags = be32_to_cpu(idle_state_flags[i]); 198 flags = be32_to_cpu(idle_state_flags[i]);
192 199
193 /* Cpuidle accepts exit_latency in us and we estimate 200 /*
194 * target residency to be 10x exit_latency 201 * Cpuidle accepts exit_latency and target_residency in us.
202 * Use default target_residency values if f/w does not expose it.
195 */ 203 */
196 latency_ns = be32_to_cpu(idle_state_latency[i]);
197 if (flags & OPAL_PM_NAP_ENABLED) { 204 if (flags & OPAL_PM_NAP_ENABLED) {
198 /* Add NAP state */ 205 /* Add NAP state */
199 strcpy(powernv_states[nr_idle_states].name, "Nap"); 206 strcpy(powernv_states[nr_idle_states].name, "Nap");
200 strcpy(powernv_states[nr_idle_states].desc, "Nap"); 207 strcpy(powernv_states[nr_idle_states].desc, "Nap");
201 powernv_states[nr_idle_states].flags = 0; 208 powernv_states[nr_idle_states].flags = 0;
202 powernv_states[nr_idle_states].exit_latency = 209 powernv_states[nr_idle_states].target_residency = 100;
203 ((unsigned int)latency_ns) / 1000;
204 powernv_states[nr_idle_states].target_residency =
205 ((unsigned int)latency_ns / 100);
206 powernv_states[nr_idle_states].enter = &nap_loop; 210 powernv_states[nr_idle_states].enter = &nap_loop;
207 nr_idle_states++; 211 } else if (flags & OPAL_PM_SLEEP_ENABLED ||
208 }
209
210 if (flags & OPAL_PM_SLEEP_ENABLED ||
211 flags & OPAL_PM_SLEEP_ENABLED_ER1) { 212 flags & OPAL_PM_SLEEP_ENABLED_ER1) {
212 /* Add FASTSLEEP state */ 213 /* Add FASTSLEEP state */
213 strcpy(powernv_states[nr_idle_states].name, "FastSleep"); 214 strcpy(powernv_states[nr_idle_states].name, "FastSleep");
214 strcpy(powernv_states[nr_idle_states].desc, "FastSleep"); 215 strcpy(powernv_states[nr_idle_states].desc, "FastSleep");
215 powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIMER_STOP; 216 powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIMER_STOP;
216 powernv_states[nr_idle_states].exit_latency = 217 powernv_states[nr_idle_states].target_residency = 300000;
217 ((unsigned int)latency_ns) / 1000;
218 powernv_states[nr_idle_states].target_residency =
219 ((unsigned int)latency_ns / 100);
220 powernv_states[nr_idle_states].enter = &fastsleep_loop; 218 powernv_states[nr_idle_states].enter = &fastsleep_loop;
221 nr_idle_states++;
222 } 219 }
220
221 powernv_states[nr_idle_states].exit_latency =
222 ((unsigned int)latency_ns[i]) / 1000;
223
224 if (!rc) {
225 powernv_states[nr_idle_states].target_residency =
226 ((unsigned int)residency_ns[i]) / 1000;
227 }
228
229 nr_idle_states++;
223 } 230 }
224 231
232 kfree(residency_ns);
233out_free_latency:
234 kfree(latency_ns);
235out:
225 return nr_idle_states; 236 return nr_idle_states;
226} 237}
227 238