aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-06-22 09:15:36 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-06-22 09:15:36 -0400
commitd461003574ebc862c2dae70c9e1ab32b1bf2cda1 (patch)
treeb21087119310109933891c42be92f5348b12a922
parent3bcda76d9d1c0c4e70d5e3b7a962e46de2e79b61 (diff)
parent78eaa10f027cf69f9bd409e64eaff902172b2327 (diff)
Merge branch 'pm-cpuidle'
* pm-cpuidle: cpuidle: powernv/pseries: Auto-promotion of snooze to deeper idle state
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c12
-rw-r--r--drivers/cpuidle/cpuidle-pseries.c11
2 files changed, 23 insertions, 0 deletions
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index 59372077ec7c..1e3ef5ec4784 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -29,18 +29,25 @@ struct cpuidle_driver powernv_idle_driver = {
29 29
30static int max_idle_state; 30static int max_idle_state;
31static struct cpuidle_state *cpuidle_state_table; 31static struct cpuidle_state *cpuidle_state_table;
32static u64 snooze_timeout;
33static bool snooze_timeout_en;
32 34
33static int snooze_loop(struct cpuidle_device *dev, 35static int snooze_loop(struct cpuidle_device *dev,
34 struct cpuidle_driver *drv, 36 struct cpuidle_driver *drv,
35 int index) 37 int index)
36{ 38{
39 u64 snooze_exit_time;
40
37 local_irq_enable(); 41 local_irq_enable();
38 set_thread_flag(TIF_POLLING_NRFLAG); 42 set_thread_flag(TIF_POLLING_NRFLAG);
39 43
44 snooze_exit_time = get_tb() + snooze_timeout;
40 ppc64_runlatch_off(); 45 ppc64_runlatch_off();
41 while (!need_resched()) { 46 while (!need_resched()) {
42 HMT_low(); 47 HMT_low();
43 HMT_very_low(); 48 HMT_very_low();
49 if (snooze_timeout_en && get_tb() > snooze_exit_time)
50 break;
44 } 51 }
45 52
46 HMT_medium(); 53 HMT_medium();
@@ -252,6 +259,11 @@ static int powernv_idle_probe(void)
252 cpuidle_state_table = powernv_states; 259 cpuidle_state_table = powernv_states;
253 /* Device tree can indicate more idle states */ 260 /* Device tree can indicate more idle states */
254 max_idle_state = powernv_add_idle_states(); 261 max_idle_state = powernv_add_idle_states();
262 if (max_idle_state > 1) {
263 snooze_timeout_en = true;
264 snooze_timeout = powernv_states[1].target_residency *
265 tb_ticks_per_usec;
266 }
255 } else 267 } else
256 return -ENODEV; 268 return -ENODEV;
257 269
diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c
index bb9e2b6f3ecc..07135e009d8b 100644
--- a/drivers/cpuidle/cpuidle-pseries.c
+++ b/drivers/cpuidle/cpuidle-pseries.c
@@ -27,6 +27,8 @@ struct cpuidle_driver pseries_idle_driver = {
27 27
28static int max_idle_state; 28static int max_idle_state;
29static struct cpuidle_state *cpuidle_state_table; 29static struct cpuidle_state *cpuidle_state_table;
30static u64 snooze_timeout;
31static bool snooze_timeout_en;
30 32
31static inline void idle_loop_prolog(unsigned long *in_purr) 33static inline void idle_loop_prolog(unsigned long *in_purr)
32{ 34{
@@ -58,14 +60,18 @@ static int snooze_loop(struct cpuidle_device *dev,
58 int index) 60 int index)
59{ 61{
60 unsigned long in_purr; 62 unsigned long in_purr;
63 u64 snooze_exit_time;
61 64
62 idle_loop_prolog(&in_purr); 65 idle_loop_prolog(&in_purr);
63 local_irq_enable(); 66 local_irq_enable();
64 set_thread_flag(TIF_POLLING_NRFLAG); 67 set_thread_flag(TIF_POLLING_NRFLAG);
68 snooze_exit_time = get_tb() + snooze_timeout;
65 69
66 while (!need_resched()) { 70 while (!need_resched()) {
67 HMT_low(); 71 HMT_low();
68 HMT_very_low(); 72 HMT_very_low();
73 if (snooze_timeout_en && get_tb() > snooze_exit_time)
74 break;
69 } 75 }
70 76
71 HMT_medium(); 77 HMT_medium();
@@ -244,6 +250,11 @@ static int pseries_idle_probe(void)
244 } else 250 } else
245 return -ENODEV; 251 return -ENODEV;
246 252
253 if (max_idle_state > 1) {
254 snooze_timeout_en = true;
255 snooze_timeout = cpuidle_state_table[1].target_residency *
256 tb_ticks_per_usec;
257 }
247 return 0; 258 return 0;
248} 259}
249 260