diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-06-22 09:15:36 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-06-22 09:15:36 -0400 |
commit | d461003574ebc862c2dae70c9e1ab32b1bf2cda1 (patch) | |
tree | b21087119310109933891c42be92f5348b12a922 | |
parent | 3bcda76d9d1c0c4e70d5e3b7a962e46de2e79b61 (diff) | |
parent | 78eaa10f027cf69f9bd409e64eaff902172b2327 (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.c | 12 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-pseries.c | 11 |
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 | ||
30 | static int max_idle_state; | 30 | static int max_idle_state; |
31 | static struct cpuidle_state *cpuidle_state_table; | 31 | static struct cpuidle_state *cpuidle_state_table; |
32 | static u64 snooze_timeout; | ||
33 | static bool snooze_timeout_en; | ||
32 | 34 | ||
33 | static int snooze_loop(struct cpuidle_device *dev, | 35 | static 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 | ||
28 | static int max_idle_state; | 28 | static int max_idle_state; |
29 | static struct cpuidle_state *cpuidle_state_table; | 29 | static struct cpuidle_state *cpuidle_state_table; |
30 | static u64 snooze_timeout; | ||
31 | static bool snooze_timeout_en; | ||
30 | 32 | ||
31 | static inline void idle_loop_prolog(unsigned long *in_purr) | 33 | static 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 | ||