aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/cpuidle/cpuidle.c13
-rw-r--r--include/linux/cpuidle.h7
-rw-r--r--kernel/sched/idle.c13
3 files changed, 26 insertions, 7 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index c73207abb5a4..afc005b917fe 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -97,7 +97,17 @@ static int find_deepest_state(struct cpuidle_driver *drv,
97 return ret; 97 return ret;
98} 98}
99 99
100#ifdef CONFIG_SUSPEND 100/* Set the current cpu to use the deepest idle state, override governors */
101void cpuidle_use_deepest_state(bool enable)
102{
103 struct cpuidle_device *dev;
104
105 preempt_disable();
106 dev = cpuidle_get_device();
107 dev->use_deepest_state = enable;
108 preempt_enable();
109}
110
101/** 111/**
102 * cpuidle_find_deepest_state - Find the deepest available idle state. 112 * cpuidle_find_deepest_state - Find the deepest available idle state.
103 * @drv: cpuidle driver for the given CPU. 113 * @drv: cpuidle driver for the given CPU.
@@ -109,6 +119,7 @@ int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
109 return find_deepest_state(drv, dev, UINT_MAX, 0, false); 119 return find_deepest_state(drv, dev, UINT_MAX, 0, false);
110} 120}
111 121
122#ifdef CONFIG_SUSPEND
112static void enter_freeze_proper(struct cpuidle_driver *drv, 123static void enter_freeze_proper(struct cpuidle_driver *drv,
113 struct cpuidle_device *dev, int index) 124 struct cpuidle_device *dev, int index)
114{ 125{
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 15deea449edc..da346f2817a8 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -74,6 +74,7 @@ struct cpuidle_driver_kobj;
74struct cpuidle_device { 74struct cpuidle_device {
75 unsigned int registered:1; 75 unsigned int registered:1;
76 unsigned int enabled:1; 76 unsigned int enabled:1;
77 unsigned int use_deepest_state:1;
77 unsigned int cpu; 78 unsigned int cpu;
78 79
79 int last_residency; 80 int last_residency;
@@ -192,11 +193,12 @@ static inline struct cpuidle_driver *cpuidle_get_cpu_driver(
192static inline struct cpuidle_device *cpuidle_get_device(void) {return NULL; } 193static inline struct cpuidle_device *cpuidle_get_device(void) {return NULL; }
193#endif 194#endif
194 195
195#if defined(CONFIG_CPU_IDLE) && defined(CONFIG_SUSPEND) 196#ifdef CONFIG_CPU_IDLE
196extern int cpuidle_find_deepest_state(struct cpuidle_driver *drv, 197extern int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
197 struct cpuidle_device *dev); 198 struct cpuidle_device *dev);
198extern int cpuidle_enter_freeze(struct cpuidle_driver *drv, 199extern int cpuidle_enter_freeze(struct cpuidle_driver *drv,
199 struct cpuidle_device *dev); 200 struct cpuidle_device *dev);
201extern void cpuidle_use_deepest_state(bool enable);
200#else 202#else
201static inline int cpuidle_find_deepest_state(struct cpuidle_driver *drv, 203static inline int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
202 struct cpuidle_device *dev) 204 struct cpuidle_device *dev)
@@ -204,6 +206,9 @@ static inline int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
204static inline int cpuidle_enter_freeze(struct cpuidle_driver *drv, 206static inline int cpuidle_enter_freeze(struct cpuidle_driver *drv,
205 struct cpuidle_device *dev) 207 struct cpuidle_device *dev)
206{return -ENODEV; } 208{return -ENODEV; }
209static inline void cpuidle_use_deepest_state(bool enable)
210{
211}
207#endif 212#endif
208 213
209/* kernel/sched/idle.c */ 214/* kernel/sched/idle.c */
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index 1d8718d5300d..513e4dfeeae7 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -164,11 +164,14 @@ static void cpuidle_idle_call(void)
164 * timekeeping to prevent timer interrupts from kicking us out of idle 164 * timekeeping to prevent timer interrupts from kicking us out of idle
165 * until a proper wakeup interrupt happens. 165 * until a proper wakeup interrupt happens.
166 */ 166 */
167 if (idle_should_freeze()) { 167
168 entered_state = cpuidle_enter_freeze(drv, dev); 168 if (idle_should_freeze() || dev->use_deepest_state) {
169 if (entered_state > 0) { 169 if (idle_should_freeze()) {
170 local_irq_enable(); 170 entered_state = cpuidle_enter_freeze(drv, dev);
171 goto exit_idle; 171 if (entered_state > 0) {
172 local_irq_enable();
173 goto exit_idle;
174 }
172 } 175 }
173 176
174 next_state = cpuidle_find_deepest_state(drv, dev); 177 next_state = cpuidle_find_deepest_state(drv, dev);