Skip to content

Commit 99e98d3

Browse files
committed
cpuidle: Consolidate disabled state checks
There are two reasons why CPU idle states may be disabled: either because the driver has disabled them or because they have been disabled by user space via sysfs. In the former case, the state's "disabled" flag is set once during the initialization of the driver and it is never cleared later (it is read-only effectively). In the latter case, the "disable" field of the given state's cpuidle_state_usage struct is set and it may be changed via sysfs. Thus checking whether or not an idle state has been disabled involves reading these two flags every time. In order to avoid the additional check of the state's "disabled" flag (which is effectively read-only anyway), use the value of it at the init time to set a (new) flag in the "disable" field of that state's cpuidle_state_usage structure and use the sysfs interface to manipulate another (new) flag in it. This way the state is disabled whenever the "disable" field of its cpuidle_state_usage structure is nonzero, whatever the reason, and it is the only place to look into to check whether or not the state has been disabled. Signed-off-by: Rafael J. Wysocki <[email protected]> Acked-by: Daniel Lezcano <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]>
1 parent fa583f7 commit 99e98d3

File tree

7 files changed

+54
-48
lines changed

7 files changed

+54
-48
lines changed

drivers/cpuidle/cpuidle-powernv.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,10 @@ static u64 get_snooze_timeout(struct cpuidle_device *dev,
5656
return default_snooze_timeout;
5757

5858
for (i = index + 1; i < drv->state_count; i++) {
59-
struct cpuidle_state *s = &drv->states[i];
60-
struct cpuidle_state_usage *su = &dev->states_usage[i];
61-
62-
if (s->disabled || su->disable)
59+
if (dev->states_usage[i].disable)
6360
continue;
6461

65-
return s->target_residency * tb_ticks_per_usec;
62+
return drv->states[i].target_residency * tb_ticks_per_usec;
6663
}
6764

6865
return default_snooze_timeout;

drivers/cpuidle/cpuidle.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,12 @@ static int find_deepest_state(struct cpuidle_driver *drv,
8484

8585
for (i = 1; i < drv->state_count; i++) {
8686
struct cpuidle_state *s = &drv->states[i];
87-
struct cpuidle_state_usage *su = &dev->states_usage[i];
8887

89-
if (s->disabled || su->disable || s->exit_latency <= latency_req
90-
|| s->exit_latency > max_latency
91-
|| (s->flags & forbidden_flags)
92-
|| (s2idle && !s->enter_s2idle))
88+
if (dev->states_usage[i].disable ||
89+
s->exit_latency <= latency_req ||
90+
s->exit_latency > max_latency ||
91+
(s->flags & forbidden_flags) ||
92+
(s2idle && !s->enter_s2idle))
9393
continue;
9494

9595
latency_req = s->exit_latency;
@@ -265,8 +265,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
265265

266266
if (diff < drv->states[entered_state].target_residency) {
267267
for (i = entered_state - 1; i >= 0; i--) {
268-
if (drv->states[i].disabled ||
269-
dev->states_usage[i].disable)
268+
if (dev->states_usage[i].disable)
270269
continue;
271270

272271
/* Shallower states are enabled, so update. */
@@ -275,8 +274,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
275274
}
276275
} else if (diff > delay) {
277276
for (i = entered_state + 1; i < drv->state_count; i++) {
278-
if (drv->states[i].disabled ||
279-
dev->states_usage[i].disable)
277+
if (dev->states_usage[i].disable)
280278
continue;
281279

282280
/*
@@ -380,7 +378,7 @@ u64 cpuidle_poll_time(struct cpuidle_driver *drv,
380378

381379
limit_ns = TICK_NSEC;
382380
for (i = 1; i < drv->state_count; i++) {
383-
if (drv->states[i].disabled || dev->states_usage[i].disable)
381+
if (dev->states_usage[i].disable)
384382
continue;
385383

386384
limit_ns = (u64)drv->states[i].target_residency * NSEC_PER_USEC;
@@ -567,12 +565,16 @@ static void __cpuidle_device_init(struct cpuidle_device *dev)
567565
*/
568566
static int __cpuidle_register_device(struct cpuidle_device *dev)
569567
{
570-
int ret;
571568
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
569+
int i, ret;
572570

573571
if (!try_module_get(drv->owner))
574572
return -EINVAL;
575573

574+
for (i = 0; i < drv->state_count; i++)
575+
if (drv->states[i].disabled)
576+
dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER;
577+
576578
per_cpu(cpuidle_devices, dev->cpu) = dev;
577579
list_add(&dev->device_list, &cpuidle_detected_devices);
578580

drivers/cpuidle/governors/ladder.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ static int ladder_select_state(struct cpuidle_driver *drv,
8484

8585
/* consider promotion */
8686
if (last_idx < drv->state_count - 1 &&
87-
!drv->states[last_idx + 1].disabled &&
8887
!dev->states_usage[last_idx + 1].disable &&
8988
last_residency > last_state->threshold.promotion_time &&
9089
drv->states[last_idx + 1].exit_latency <= latency_req) {
@@ -98,8 +97,7 @@ static int ladder_select_state(struct cpuidle_driver *drv,
9897

9998
/* consider demotion */
10099
if (last_idx > first_idx &&
101-
(drv->states[last_idx].disabled ||
102-
dev->states_usage[last_idx].disable ||
100+
(dev->states_usage[last_idx].disable ||
103101
drv->states[last_idx].exit_latency > latency_req)) {
104102
int i;
105103

drivers/cpuidle/governors/menu.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
298298
if (unlikely(drv->state_count <= 1 || latency_req == 0) ||
299299
((data->next_timer_us < drv->states[1].target_residency ||
300300
latency_req < drv->states[1].exit_latency) &&
301-
!drv->states[0].disabled && !dev->states_usage[0].disable)) {
301+
!dev->states_usage[0].disable)) {
302302
/*
303303
* In this case state[0] will be used no matter what, so return
304304
* it right away and keep the tick running if state[0] is a
@@ -349,9 +349,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
349349
idx = -1;
350350
for (i = 0; i < drv->state_count; i++) {
351351
struct cpuidle_state *s = &drv->states[i];
352-
struct cpuidle_state_usage *su = &dev->states_usage[i];
353352

354-
if (s->disabled || su->disable)
353+
if (dev->states_usage[i].disable)
355354
continue;
356355

357356
if (idx == -1)
@@ -422,8 +421,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
422421
* tick, so try to correct that.
423422
*/
424423
for (i = idx - 1; i >= 0; i--) {
425-
if (drv->states[i].disabled ||
426-
dev->states_usage[i].disable)
424+
if (dev->states_usage[i].disable)
427425
continue;
428426

429427
idx = i;

drivers/cpuidle/governors/teo.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ static int teo_find_shallower_state(struct cpuidle_driver *drv,
212212
int i;
213213

214214
for (i = state_idx - 1; i >= 0; i--) {
215-
if (drv->states[i].disabled || dev->states_usage[i].disable)
215+
if (dev->states_usage[i].disable)
216216
continue;
217217

218218
state_idx = i;
@@ -256,9 +256,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
256256

257257
for (i = 0; i < drv->state_count; i++) {
258258
struct cpuidle_state *s = &drv->states[i];
259-
struct cpuidle_state_usage *su = &dev->states_usage[i];
260259

261-
if (s->disabled || su->disable) {
260+
if (dev->states_usage[i].disable) {
262261
/*
263262
* Ignore disabled states with target residencies beyond
264263
* the anticipated idle duration.

drivers/cpuidle/sysfs.c

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -255,25 +255,6 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \
255255
return sprintf(buf, "%u\n", state->_name);\
256256
}
257257

258-
#define define_store_state_ull_function(_name) \
259-
static ssize_t store_state_##_name(struct cpuidle_state *state, \
260-
struct cpuidle_state_usage *state_usage, \
261-
const char *buf, size_t size) \
262-
{ \
263-
unsigned long long value; \
264-
int err; \
265-
if (!capable(CAP_SYS_ADMIN)) \
266-
return -EPERM; \
267-
err = kstrtoull(buf, 0, &value); \
268-
if (err) \
269-
return err; \
270-
if (value) \
271-
state_usage->_name = 1; \
272-
else \
273-
state_usage->_name = 0; \
274-
return size; \
275-
}
276-
277258
#define define_show_state_ull_function(_name) \
278259
static ssize_t show_state_##_name(struct cpuidle_state *state, \
279260
struct cpuidle_state_usage *state_usage, \
@@ -299,11 +280,39 @@ define_show_state_ull_function(usage)
299280
define_show_state_ull_function(time)
300281
define_show_state_str_function(name)
301282
define_show_state_str_function(desc)
302-
define_show_state_ull_function(disable)
303-
define_store_state_ull_function(disable)
304283
define_show_state_ull_function(above)
305284
define_show_state_ull_function(below)
306285

286+
static ssize_t show_state_disable(struct cpuidle_state *state,
287+
struct cpuidle_state_usage *state_usage,
288+
char *buf)
289+
{
290+
return sprintf(buf, "%llu\n",
291+
state_usage->disable & CPUIDLE_STATE_DISABLED_BY_USER);
292+
}
293+
294+
static ssize_t store_state_disable(struct cpuidle_state *state,
295+
struct cpuidle_state_usage *state_usage,
296+
const char *buf, size_t size)
297+
{
298+
unsigned int value;
299+
int err;
300+
301+
if (!capable(CAP_SYS_ADMIN))
302+
return -EPERM;
303+
304+
err = kstrtouint(buf, 0, &value);
305+
if (err)
306+
return err;
307+
308+
if (value)
309+
state_usage->disable |= CPUIDLE_STATE_DISABLED_BY_USER;
310+
else
311+
state_usage->disable &= ~CPUIDLE_STATE_DISABLED_BY_USER;
312+
313+
return size;
314+
}
315+
307316
define_one_state_ro(name, show_state_name);
308317
define_one_state_ro(desc, show_state_desc);
309318
define_one_state_ro(latency, show_state_exit_latency);

include/linux/cpuidle.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ struct cpuidle_driver;
2929
* CPUIDLE DEVICE INTERFACE *
3030
****************************/
3131

32+
#define CPUIDLE_STATE_DISABLED_BY_USER BIT(0)
33+
#define CPUIDLE_STATE_DISABLED_BY_DRIVER BIT(1)
34+
3235
struct cpuidle_state_usage {
3336
unsigned long long disable;
3437
unsigned long long usage;

0 commit comments

Comments
 (0)