Skip to content

Commit a0bfa13

Browse files
committed
cpuidle: stop depending on pm_idle
cpuidle users should call cpuidle_call_idle() directly rather than via (pm_idle)() function pointer. Architecture may choose to continue using (pm_idle)(), but cpuidle need not depend on it: my_arch_cpu_idle() ... if(cpuidle_call_idle()) pm_idle(); cc: Kevin Hilman <[email protected]> cc: Paul Mundt <[email protected]> cc: [email protected] Acked-by: H. Peter Anvin <[email protected]> Signed-off-by: Len Brown <[email protected]>
1 parent 4bfc828 commit a0bfa13

File tree

6 files changed

+33
-25
lines changed

6 files changed

+33
-25
lines changed

arch/arm/kernel/process.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/uaccess.h>
3131
#include <linux/random.h>
3232
#include <linux/hw_breakpoint.h>
33+
#include <linux/cpuidle.h>
3334

3435
#include <asm/cacheflush.h>
3536
#include <asm/leds.h>
@@ -196,7 +197,8 @@ void cpu_idle(void)
196197
cpu_relax();
197198
} else {
198199
stop_critical_timings();
199-
pm_idle();
200+
if (cpuidle_call_idle())
201+
pm_idle();
200202
start_critical_timings();
201203
/*
202204
* This will eventually be removed - pm_idle

arch/sh/kernel/idle.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
#include <linux/thread_info.h>
1717
#include <linux/irqflags.h>
1818
#include <linux/smp.h>
19+
#include <linux/cpuidle.h>
1920
#include <asm/pgalloc.h>
2021
#include <asm/system.h>
2122
#include <asm/atomic.h>
2223
#include <asm/smp.h>
2324

24-
void (*pm_idle)(void) = NULL;
25+
static void (*pm_idle)(void);
2526

2627
static int hlt_counter;
2728

@@ -100,7 +101,8 @@ void cpu_idle(void)
100101
local_irq_disable();
101102
/* Don't trace irqs off for idle */
102103
stop_critical_timings();
103-
pm_idle();
104+
if (cpuidle_call_idle())
105+
pm_idle();
104106
/*
105107
* Sanity check to ensure that pm_idle() returns
106108
* with IRQs enabled

arch/x86/kernel/process_32.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <linux/uaccess.h>
3939
#include <linux/io.h>
4040
#include <linux/kdebug.h>
41+
#include <linux/cpuidle.h>
4142

4243
#include <asm/pgtable.h>
4344
#include <asm/system.h>
@@ -109,7 +110,8 @@ void cpu_idle(void)
109110
local_irq_disable();
110111
/* Don't trace irqs off for idle */
111112
stop_critical_timings();
112-
pm_idle();
113+
if (cpuidle_idle_call())
114+
pm_idle();
113115
start_critical_timings();
114116
}
115117
tick_nohz_restart_sched_tick();

arch/x86/kernel/process_64.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <linux/uaccess.h>
3838
#include <linux/io.h>
3939
#include <linux/ftrace.h>
40+
#include <linux/cpuidle.h>
4041

4142
#include <asm/pgtable.h>
4243
#include <asm/system.h>
@@ -136,7 +137,8 @@ void cpu_idle(void)
136137
enter_idle();
137138
/* Don't trace irqs off for idle */
138139
stop_critical_timings();
139-
pm_idle();
140+
if (cpuidle_idle_call())
141+
pm_idle();
140142
start_critical_timings();
141143

142144
/* In many cases the interrupt that ended idle

drivers/cpuidle/cpuidle.c

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
2525

2626
DEFINE_MUTEX(cpuidle_lock);
2727
LIST_HEAD(cpuidle_detected_devices);
28-
static void (*pm_idle_old)(void);
2928

3029
static int enabled_devices;
3130
static int off __read_mostly;
31+
static int initialized __read_mostly;
3232

3333
int cpuidle_disabled(void)
3434
{
@@ -56,25 +56,23 @@ static int __cpuidle_register_device(struct cpuidle_device *dev);
5656
* cpuidle_idle_call - the main idle loop
5757
*
5858
* NOTE: no locks or semaphores should be used here
59+
* return non-zero on failure
5960
*/
60-
static void cpuidle_idle_call(void)
61+
int cpuidle_idle_call(void)
6162
{
6263
struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
6364
struct cpuidle_state *target_state;
6465
int next_state;
6566

67+
if (off)
68+
return -ENODEV;
69+
70+
if (!initialized)
71+
return -ENODEV;
72+
6673
/* check if the device is ready */
67-
if (!dev || !dev->enabled) {
68-
if (pm_idle_old)
69-
pm_idle_old();
70-
else
71-
#if defined(CONFIG_ARCH_HAS_DEFAULT_IDLE)
72-
default_idle();
73-
#else
74-
local_irq_enable();
75-
#endif
76-
return;
77-
}
74+
if (!dev || !dev->enabled)
75+
return -EBUSY;
7876

7977
#if 0
8078
/* shows regressions, re-enable for 2.6.29 */
@@ -99,7 +97,7 @@ static void cpuidle_idle_call(void)
9997
next_state = cpuidle_curr_governor->select(dev);
10098
if (need_resched()) {
10199
local_irq_enable();
102-
return;
100+
return 0;
103101
}
104102

105103
target_state = &dev->states[next_state];
@@ -124,17 +122,19 @@ static void cpuidle_idle_call(void)
124122
/* give the governor an opportunity to reflect on the outcome */
125123
if (cpuidle_curr_governor->reflect)
126124
cpuidle_curr_governor->reflect(dev);
125+
126+
return 0;
127127
}
128128

129129
/**
130130
* cpuidle_install_idle_handler - installs the cpuidle idle loop handler
131131
*/
132132
void cpuidle_install_idle_handler(void)
133133
{
134-
if (enabled_devices && (pm_idle != cpuidle_idle_call)) {
134+
if (enabled_devices) {
135135
/* Make sure all changes finished before we switch to new idle */
136136
smp_wmb();
137-
pm_idle = cpuidle_idle_call;
137+
initialized = 1;
138138
}
139139
}
140140

@@ -143,8 +143,8 @@ void cpuidle_install_idle_handler(void)
143143
*/
144144
void cpuidle_uninstall_idle_handler(void)
145145
{
146-
if (enabled_devices && pm_idle_old && (pm_idle != pm_idle_old)) {
147-
pm_idle = pm_idle_old;
146+
if (enabled_devices) {
147+
initialized = 0;
148148
cpuidle_kick_cpus();
149149
}
150150
}
@@ -440,8 +440,6 @@ static int __init cpuidle_init(void)
440440
if (cpuidle_disabled())
441441
return -ENODEV;
442442

443-
pm_idle_old = pm_idle;
444-
445443
ret = cpuidle_add_class_sysfs(&cpu_sysdev_class);
446444
if (ret)
447445
return ret;

include/linux/cpuidle.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ struct cpuidle_driver {
123123

124124
#ifdef CONFIG_CPU_IDLE
125125
extern void disable_cpuidle(void);
126+
extern int cpuidle_idle_call(void);
126127

127128
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
128129
struct cpuidle_driver *cpuidle_get_driver(void);
@@ -137,6 +138,7 @@ extern void cpuidle_disable_device(struct cpuidle_device *dev);
137138

138139
#else
139140
static inline void disable_cpuidle(void) { }
141+
static inline int cpuidle_idle_call(void) { return -ENODEV; }
140142

141143
static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
142144
{return -ENODEV; }

0 commit comments

Comments
 (0)