Skip to content

Commit bb8313b

Browse files
Jacob Panrafaeljw
authored andcommitted
cpuidle: Allow enforcing deepest idle state selection
When idle injection is used to cap power, we need to override the governor's choice of idle states. For this reason, make it possible the deepest idle state selection to be enforced by setting a flag on a given CPU to achieve the maximum potential power draw reduction. Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com> [ rjw: Subject & changelog ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent ed61390 commit bb8313b

File tree

3 files changed

+26
-7
lines changed

3 files changed

+26
-7
lines changed

drivers/cpuidle/cpuidle.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,17 @@ static int find_deepest_state(struct cpuidle_driver *drv,
9797
return ret;
9898
}
9999

100-
#ifdef CONFIG_SUSPEND
100+
/* Set the current cpu to use the deepest idle state, override governors */
101+
void 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+
101111
/**
102112
* cpuidle_find_deepest_state - Find the deepest available idle state.
103113
* @drv: cpuidle driver for the given CPU.
@@ -109,6 +119,7 @@ int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
109119
return find_deepest_state(drv, dev, UINT_MAX, 0, false);
110120
}
111121

122+
#ifdef CONFIG_SUSPEND
112123
static void enter_freeze_proper(struct cpuidle_driver *drv,
113124
struct cpuidle_device *dev, int index)
114125
{

include/linux/cpuidle.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct cpuidle_driver_kobj;
7474
struct cpuidle_device {
7575
unsigned int registered:1;
7676
unsigned int enabled:1;
77+
unsigned int use_deepest_state:1;
7778
unsigned int cpu;
7879

7980
int last_residency;
@@ -192,18 +193,22 @@ static inline struct cpuidle_driver *cpuidle_get_cpu_driver(
192193
static inline struct cpuidle_device *cpuidle_get_device(void) {return NULL; }
193194
#endif
194195

195-
#if defined(CONFIG_CPU_IDLE) && defined(CONFIG_SUSPEND)
196+
#ifdef CONFIG_CPU_IDLE
196197
extern int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
197198
struct cpuidle_device *dev);
198199
extern int cpuidle_enter_freeze(struct cpuidle_driver *drv,
199200
struct cpuidle_device *dev);
201+
extern void cpuidle_use_deepest_state(bool enable);
200202
#else
201203
static inline int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
202204
struct cpuidle_device *dev)
203205
{return -ENODEV; }
204206
static inline int cpuidle_enter_freeze(struct cpuidle_driver *drv,
205207
struct cpuidle_device *dev)
206208
{return -ENODEV; }
209+
static inline void cpuidle_use_deepest_state(bool enable)
210+
{
211+
}
207212
#endif
208213

209214
/* kernel/sched/idle.c */

kernel/sched/idle.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,14 @@ static void cpuidle_idle_call(void)
164164
* timekeeping to prevent timer interrupts from kicking us out of idle
165165
* until a proper wakeup interrupt happens.
166166
*/
167-
if (idle_should_freeze()) {
168-
entered_state = cpuidle_enter_freeze(drv, dev);
169-
if (entered_state > 0) {
170-
local_irq_enable();
171-
goto exit_idle;
167+
168+
if (idle_should_freeze() || dev->use_deepest_state) {
169+
if (idle_should_freeze()) {
170+
entered_state = cpuidle_enter_freeze(drv, dev);
171+
if (entered_state > 0) {
172+
local_irq_enable();
173+
goto exit_idle;
174+
}
172175
}
173176

174177
next_state = cpuidle_find_deepest_state(drv, dev);

0 commit comments

Comments
 (0)