Skip to content

Commit aa9abe2

Browse files
committed
Merge branch 'pm-cpuidle' into pm-sleep
2 parents 2c73078 + a6220fc commit aa9abe2

File tree

5 files changed

+62
-39
lines changed

5 files changed

+62
-39
lines changed

drivers/cpuidle/cpuidle.c

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ LIST_HEAD(cpuidle_detected_devices);
3232
static int enabled_devices;
3333
static int off __read_mostly;
3434
static int initialized __read_mostly;
35+
static bool use_deepest_state __read_mostly;
3536

3637
int cpuidle_disabled(void)
3738
{
@@ -65,23 +66,42 @@ int cpuidle_play_dead(void)
6566
}
6667

6768
/**
68-
* cpuidle_enabled - check if the cpuidle framework is ready
69-
* @dev: cpuidle device for this cpu
70-
* @drv: cpuidle driver for this cpu
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).
7175
*
72-
* Return 0 on success, otherwise:
73-
* -NODEV : the cpuidle framework is not available
74-
* -EBUSY : the cpuidle framework is not initialized
76+
* This function can only be called after cpuidle_pause() to avoid races.
7577
*/
76-
int cpuidle_enabled(struct cpuidle_driver *drv, struct cpuidle_device *dev)
78+
void cpuidle_use_deepest_state(bool enable)
7779
{
78-
if (off || !initialized)
79-
return -ENODEV;
80+
use_deepest_state = enable;
81+
}
8082

81-
if (!drv || !dev || !dev->enabled)
82-
return -EBUSY;
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+
*/
88+
static 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;
8393

84-
return 0;
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;
85105
}
86106

87107
/**
@@ -138,6 +158,15 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
138158
*/
139159
int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
140160
{
161+
if (off || !initialized)
162+
return -ENODEV;
163+
164+
if (!drv || !dev || !dev->enabled)
165+
return -EBUSY;
166+
167+
if (unlikely(use_deepest_state))
168+
return cpuidle_find_deepest_state(drv, dev);
169+
141170
return cpuidle_curr_governor->select(drv, dev);
142171
}
143172

@@ -169,7 +198,7 @@ int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev,
169198
*/
170199
void cpuidle_reflect(struct cpuidle_device *dev, int index)
171200
{
172-
if (cpuidle_curr_governor->reflect)
201+
if (cpuidle_curr_governor->reflect && !unlikely(use_deepest_state))
173202
cpuidle_curr_governor->reflect(dev, index);
174203
}
175204

drivers/cpuidle/governors/menu.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
296296
data->needs_update = 0;
297297
}
298298

299-
data->last_state_idx = 0;
299+
data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1;
300300

301301
/* Special case when user has set very strict latency requirement */
302302
if (unlikely(latency_req == 0))
@@ -310,13 +310,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
310310

311311
data->bucket = which_bucket(data->next_timer_us);
312312

313-
/*
314-
* if the correction factor is 0 (eg first time init or cpu hotplug
315-
* etc), we actually want to start out with a unity factor.
316-
*/
317-
if (data->correction_factor[data->bucket] == 0)
318-
data->correction_factor[data->bucket] = RESOLUTION * DECAY;
319-
320313
/*
321314
* Force the result of multiplication to be 64 bits even if both
322315
* operands are 32 bits.
@@ -466,9 +459,17 @@ static int menu_enable_device(struct cpuidle_driver *drv,
466459
struct cpuidle_device *dev)
467460
{
468461
struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
462+
int i;
469463

470464
memset(data, 0, sizeof(struct menu_device));
471465

466+
/*
467+
* if the correction factor is 0 (eg first time init or cpu hotplug
468+
* etc), we actually want to start out with a unity factor.
469+
*/
470+
for(i = 0; i < BUCKETS; i++)
471+
data->correction_factor[i] = RESOLUTION * DECAY;
472+
472473
return 0;
473474
}
474475

include/linux/cpuidle.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,6 @@ struct cpuidle_driver {
120120
#ifdef CONFIG_CPU_IDLE
121121
extern void disable_cpuidle(void);
122122

123-
extern int cpuidle_enabled(struct cpuidle_driver *drv,
124-
struct cpuidle_device *dev);
125123
extern int cpuidle_select(struct cpuidle_driver *drv,
126124
struct cpuidle_device *dev);
127125
extern int cpuidle_enter(struct cpuidle_driver *drv,
@@ -145,13 +143,11 @@ extern void cpuidle_resume(void);
145143
extern int cpuidle_enable_device(struct cpuidle_device *dev);
146144
extern void cpuidle_disable_device(struct cpuidle_device *dev);
147145
extern int cpuidle_play_dead(void);
146+
extern void cpuidle_use_deepest_state(bool enable);
148147

149148
extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev);
150149
#else
151150
static inline void disable_cpuidle(void) { }
152-
static inline int cpuidle_enabled(struct cpuidle_driver *drv,
153-
struct cpuidle_device *dev)
154-
{return -ENODEV; }
155151
static inline int cpuidle_select(struct cpuidle_driver *drv,
156152
struct cpuidle_device *dev)
157153
{return -ENODEV; }
@@ -180,6 +176,7 @@ static inline int cpuidle_enable_device(struct cpuidle_device *dev)
180176
{return -ENODEV; }
181177
static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
182178
static inline int cpuidle_play_dead(void) {return -ENODEV; }
179+
static inline void cpuidle_use_deepest_state(bool enable) {}
183180
static inline struct cpuidle_driver *cpuidle_get_cpu_driver(
184181
struct cpuidle_device *dev) {return NULL; }
185182
#endif

kernel/power/suspend.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,11 @@ static void freeze_begin(void)
5454

5555
static void freeze_enter(void)
5656
{
57+
cpuidle_use_deepest_state(true);
5758
cpuidle_resume();
5859
wait_event(suspend_freeze_wait_head, suspend_freeze_wake);
5960
cpuidle_pause();
61+
cpuidle_use_deepest_state(false);
6062
}
6163

6264
void freeze_wake(void)

kernel/sched/idle.c

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,13 @@ static int cpuidle_idle_call(void)
101101
rcu_idle_enter();
102102

103103
/*
104-
* Check if the cpuidle framework is ready, otherwise fallback
105-
* to the default arch specific idle method
104+
* Ask the cpuidle framework to choose a convenient idle state.
105+
* Fall back to the default arch specific idle method on errors.
106106
*/
107-
ret = cpuidle_enabled(drv, dev);
108-
109-
if (!ret) {
110-
/*
111-
* Ask the governor to choose an idle state it thinks
112-
* it is convenient to go to. There is *always* a
113-
* convenient idle state
114-
*/
115-
next_state = cpuidle_select(drv, dev);
107+
next_state = cpuidle_select(drv, dev);
116108

109+
ret = next_state;
110+
if (ret >= 0) {
117111
/*
118112
* The idle task must be scheduled, it is pointless to
119113
* go to idle, just update no idle residency and get
@@ -140,7 +134,7 @@ static int cpuidle_idle_call(void)
140134
CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
141135
&dev->cpu);
142136

143-
if (!ret) {
137+
if (ret >= 0) {
144138
trace_cpu_idle_rcuidle(next_state, dev->cpu);
145139

146140
/*
@@ -175,7 +169,7 @@ static int cpuidle_idle_call(void)
175169
* We can't use the cpuidle framework, let's use the default
176170
* idle routine
177171
*/
178-
if (ret)
172+
if (ret < 0)
179173
arch_cpu_idle();
180174

181175
__current_set_polling();

0 commit comments

Comments
 (0)