aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorShreyas B. Prabhu <shreyas@linux.vnet.ibm.com>2016-07-08 02:20:52 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2016-07-15 06:18:42 -0400
commit3005c597ba46480b42e1fea3512c408f1830b816 (patch)
tree296bc85154cee248c06f73aaa00ffcc5dba8251a /drivers/cpuidle
parent957efcedeef4b02f2f7e5776d64448e5c40462b4 (diff)
cpuidle/powernv: Add support for POWER ISA v3 idle states
POWER ISA v3 defines a new idle processor core mechanism. In summary, a) new instruction named stop is added. b) new per thread SPR named PSSCR is added which controls the behavior of stop instruction. Supported idle states and value to be written to PSSCR register to enter any idle state is exposed via ibm,cpu-idle-state-names and ibm,cpu-idle-state-psscr respectively. To enter an idle state, platform provided power_stop() needs to be invoked with the appropriate PSSCR value. This patch adds support for this new mechanism in cpuidle powernv driver. Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Cc: Daniel Lezcano <daniel.lezcano@linaro.org> Cc: Rob Herring <robh+dt@kernel.org> Cc: Lorenzo Pieralisi <Lorenzo.Pieralisi@arm.com> Cc: linux-pm@vger.kernel.org Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Paul Mackerras <paulus@ozlabs.org> Cc: linuxppc-dev@lists.ozlabs.org Reviewed-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com> Signed-off-by: Shreyas B. Prabhu <shreyas@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index 600bbe1a7aad..f7ca891b5b59 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -20,6 +20,8 @@
20#include <asm/opal.h> 20#include <asm/opal.h>
21#include <asm/runlatch.h> 21#include <asm/runlatch.h>
22 22
23#define POWERNV_THRESHOLD_LATENCY_NS 200000
24
23struct cpuidle_driver powernv_idle_driver = { 25struct cpuidle_driver powernv_idle_driver = {
24 .name = "powernv_idle", 26 .name = "powernv_idle",
25 .owner = THIS_MODULE, 27 .owner = THIS_MODULE,
@@ -27,6 +29,9 @@ struct cpuidle_driver powernv_idle_driver = {
27 29
28static int max_idle_state; 30static int max_idle_state;
29static struct cpuidle_state *cpuidle_state_table; 31static struct cpuidle_state *cpuidle_state_table;
32
33static u64 stop_psscr_table[CPUIDLE_STATE_MAX];
34
30static u64 snooze_timeout; 35static u64 snooze_timeout;
31static bool snooze_timeout_en; 36static bool snooze_timeout_en;
32 37
@@ -91,6 +96,17 @@ static int fastsleep_loop(struct cpuidle_device *dev,
91 return index; 96 return index;
92} 97}
93#endif 98#endif
99
100static int stop_loop(struct cpuidle_device *dev,
101 struct cpuidle_driver *drv,
102 int index)
103{
104 ppc64_runlatch_off();
105 power9_idle_stop(stop_psscr_table[index]);
106 ppc64_runlatch_on();
107 return index;
108}
109
94/* 110/*
95 * States for dedicated partition case. 111 * States for dedicated partition case.
96 */ 112 */
@@ -169,6 +185,8 @@ static int powernv_add_idle_states(void)
169 u32 latency_ns[CPUIDLE_STATE_MAX]; 185 u32 latency_ns[CPUIDLE_STATE_MAX];
170 u32 residency_ns[CPUIDLE_STATE_MAX]; 186 u32 residency_ns[CPUIDLE_STATE_MAX];
171 u32 flags[CPUIDLE_STATE_MAX]; 187 u32 flags[CPUIDLE_STATE_MAX];
188 u64 psscr_val[CPUIDLE_STATE_MAX];
189 const char *names[CPUIDLE_STATE_MAX];
172 int i, rc; 190 int i, rc;
173 191
174 /* Currently we have snooze statically defined */ 192 /* Currently we have snooze statically defined */
@@ -207,11 +225,34 @@ static int powernv_add_idle_states(void)
207 pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT\n"); 225 pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT\n");
208 goto out; 226 goto out;
209 } 227 }
228 if (of_property_read_string_array(power_mgt,
229 "ibm,cpu-idle-state-names", names, dt_idle_states) < 0) {
230 pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-names in DT\n");
231 goto out;
232 }
233
234 /*
235 * If the idle states use stop instruction, probe for psscr values
236 * which are necessary to specify required stop level.
237 */
238 if (flags[0] & (OPAL_PM_STOP_INST_FAST | OPAL_PM_STOP_INST_DEEP))
239 if (of_property_read_u64_array(power_mgt,
240 "ibm,cpu-idle-state-psscr", psscr_val, dt_idle_states)) {
241 pr_warn("cpuidle-powernv: missing ibm,cpu-idle-states-psscr in DT\n");
242 goto out;
243 }
210 244
211 rc = of_property_read_u32_array(power_mgt, 245 rc = of_property_read_u32_array(power_mgt,
212 "ibm,cpu-idle-state-residency-ns", residency_ns, dt_idle_states); 246 "ibm,cpu-idle-state-residency-ns", residency_ns, dt_idle_states);
213 247
214 for (i = 0; i < dt_idle_states; i++) { 248 for (i = 0; i < dt_idle_states; i++) {
249 /*
250 * If an idle state has exit latency beyond
251 * POWERNV_THRESHOLD_LATENCY_NS then don't use it
252 * in cpu-idle.
253 */
254 if (latency_ns[i] > POWERNV_THRESHOLD_LATENCY_NS)
255 continue;
215 256
216 /* 257 /*
217 * Cpuidle accepts exit_latency and target_residency in us. 258 * Cpuidle accepts exit_latency and target_residency in us.
@@ -224,6 +265,16 @@ static int powernv_add_idle_states(void)
224 powernv_states[nr_idle_states].flags = 0; 265 powernv_states[nr_idle_states].flags = 0;
225 powernv_states[nr_idle_states].target_residency = 100; 266 powernv_states[nr_idle_states].target_residency = 100;
226 powernv_states[nr_idle_states].enter = nap_loop; 267 powernv_states[nr_idle_states].enter = nap_loop;
268 } else if ((flags[i] & OPAL_PM_STOP_INST_FAST) &&
269 !(flags[i] & OPAL_PM_TIMEBASE_STOP)) {
270 strncpy(powernv_states[nr_idle_states].name,
271 names[i], CPUIDLE_NAME_LEN);
272 strncpy(powernv_states[nr_idle_states].desc,
273 names[i], CPUIDLE_NAME_LEN);
274 powernv_states[nr_idle_states].flags = 0;
275
276 powernv_states[nr_idle_states].enter = stop_loop;
277 stop_psscr_table[nr_idle_states] = psscr_val[i];
227 } 278 }
228 279
229 /* 280 /*
@@ -239,6 +290,16 @@ static int powernv_add_idle_states(void)
239 powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIMER_STOP; 290 powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIMER_STOP;
240 powernv_states[nr_idle_states].target_residency = 300000; 291 powernv_states[nr_idle_states].target_residency = 300000;
241 powernv_states[nr_idle_states].enter = fastsleep_loop; 292 powernv_states[nr_idle_states].enter = fastsleep_loop;
293 } else if ((flags[i] & OPAL_PM_STOP_INST_DEEP) &&
294 (flags[i] & OPAL_PM_TIMEBASE_STOP)) {
295 strncpy(powernv_states[nr_idle_states].name,
296 names[i], CPUIDLE_NAME_LEN);
297 strncpy(powernv_states[nr_idle_states].desc,
298 names[i], CPUIDLE_NAME_LEN);
299
300 powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIMER_STOP;
301 powernv_states[nr_idle_states].enter = stop_loop;
302 stop_psscr_table[nr_idle_states] = psscr_val[i];
242 } 303 }
243#endif 304#endif
244 powernv_states[nr_idle_states].exit_latency = 305 powernv_states[nr_idle_states].exit_latency =