aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle/cpuidle.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-05-04 18:51:54 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-05-06 19:49:28 -0400
commita6220fc19afc07fe77cfd16f5b8e568615517091 (patch)
tree1f79cd9dc6610db3ca394dcd4f61a3b109d1069d /drivers/cpuidle/cpuidle.c
parentbed4d597a0f99b380d24ab3a9da47b62cbf1ad0e (diff)
PM / suspend: Always use deepest C-state in the "freeze" sleep state
If freeze_enter() is called, we want to bypass the current cpuidle governor and always use the deepest available (that is, not disabled) C-state, because we want to save as much energy as reasonably possible then and runtime latency constraints don't matter at that point, since the system is in a sleep state anyway. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Aubrey Li <aubrey.li@linux.intel.com>
Diffstat (limited to 'drivers/cpuidle/cpuidle.c')
-rw-r--r--drivers/cpuidle/cpuidle.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index f38359f64cc6..cb7019977c50 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -32,6 +32,7 @@ LIST_HEAD(cpuidle_detected_devices);
32static int enabled_devices; 32static int enabled_devices;
33static int off __read_mostly; 33static int off __read_mostly;
34static int initialized __read_mostly; 34static int initialized __read_mostly;
35static bool use_deepest_state __read_mostly;
35 36
36int cpuidle_disabled(void) 37int cpuidle_disabled(void)
37{ 38{
@@ -65,6 +66,45 @@ int cpuidle_play_dead(void)
65} 66}
66 67
67/** 68/**
69 * cpuidle_use_deepest_state - Enable/disable the "deepest idle" mode.
70 * @enable: Whether enable or disable the feature.
71 *
72 * If the "deepest idle" mode is enabled, cpuidle will ignore the governor and
73 * always use the state with the greatest exit latency (out of the states that
74 * are not disabled).
75 *
76 * This function can only be called after cpuidle_pause() to avoid races.
77 */
78void cpuidle_use_deepest_state(bool enable)
79{
80 use_deepest_state = enable;
81}
82
83/**
84 * cpuidle_find_deepest_state - Find the state of the greatest exit latency.
85 * @drv: cpuidle driver for a given CPU.
86 * @dev: cpuidle device for a given CPU.
87 */
88static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
89 struct cpuidle_device *dev)
90{
91 unsigned int latency_req = 0;
92 int i, ret = CPUIDLE_DRIVER_STATE_START - 1;
93
94 for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
95 struct cpuidle_state *s = &drv->states[i];
96 struct cpuidle_state_usage *su = &dev->states_usage[i];
97
98 if (s->disabled || su->disable || s->exit_latency <= latency_req)
99 continue;
100
101 latency_req = s->exit_latency;
102 ret = i;
103 }
104 return ret;
105}
106
107/**
68 * cpuidle_enter_state - enter the state and update stats 108 * cpuidle_enter_state - enter the state and update stats
69 * @dev: cpuidle device for this cpu 109 * @dev: cpuidle device for this cpu
70 * @drv: cpuidle driver for this cpu 110 * @drv: cpuidle driver for this cpu
@@ -124,6 +164,9 @@ int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
124 if (!drv || !dev || !dev->enabled) 164 if (!drv || !dev || !dev->enabled)
125 return -EBUSY; 165 return -EBUSY;
126 166
167 if (unlikely(use_deepest_state))
168 return cpuidle_find_deepest_state(drv, dev);
169
127 return cpuidle_curr_governor->select(drv, dev); 170 return cpuidle_curr_governor->select(drv, dev);
128} 171}
129 172
@@ -155,7 +198,7 @@ int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev,
155 */ 198 */
156void cpuidle_reflect(struct cpuidle_device *dev, int index) 199void cpuidle_reflect(struct cpuidle_device *dev, int index)
157{ 200{
158 if (cpuidle_curr_governor->reflect) 201 if (cpuidle_curr_governor->reflect && !unlikely(use_deepest_state))
159 cpuidle_curr_governor->reflect(dev, index); 202 cpuidle_curr_governor->reflect(dev, index);
160} 203}
161 204