aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/kernel/process.c4
-rw-r--r--arch/sh/kernel/idle.c6
-rw-r--r--arch/x86/kernel/process_32.c4
-rw-r--r--arch/x86/kernel/process_64.c4
-rw-r--r--drivers/cpuidle/cpuidle.c38
-rw-r--r--include/linux/cpuidle.h2
6 files changed, 33 insertions, 25 deletions
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 5e1e54197227..d7ee0d4c072d 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -30,6 +30,7 @@
30#include <linux/uaccess.h> 30#include <linux/uaccess.h>
31#include <linux/random.h> 31#include <linux/random.h>
32#include <linux/hw_breakpoint.h> 32#include <linux/hw_breakpoint.h>
33#include <linux/cpuidle.h>
33 34
34#include <asm/cacheflush.h> 35#include <asm/cacheflush.h>
35#include <asm/leds.h> 36#include <asm/leds.h>
@@ -196,7 +197,8 @@ void cpu_idle(void)
196 cpu_relax(); 197 cpu_relax();
197 } else { 198 } else {
198 stop_critical_timings(); 199 stop_critical_timings();
199 pm_idle(); 200 if (cpuidle_call_idle())
201 pm_idle();
200 start_critical_timings(); 202 start_critical_timings();
201 /* 203 /*
202 * This will eventually be removed - pm_idle 204 * This will eventually be removed - pm_idle
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 425d604e3a28..9c7099ebfe14 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -16,12 +16,13 @@
16#include <linux/thread_info.h> 16#include <linux/thread_info.h>
17#include <linux/irqflags.h> 17#include <linux/irqflags.h>
18#include <linux/smp.h> 18#include <linux/smp.h>
19#include <linux/cpuidle.h>
19#include <asm/pgalloc.h> 20#include <asm/pgalloc.h>
20#include <asm/system.h> 21#include <asm/system.h>
21#include <asm/atomic.h> 22#include <asm/atomic.h>
22#include <asm/smp.h> 23#include <asm/smp.h>
23 24
24void (*pm_idle)(void) = NULL; 25static void (*pm_idle)(void);
25 26
26static int hlt_counter; 27static int hlt_counter;
27 28
@@ -100,7 +101,8 @@ void cpu_idle(void)
100 local_irq_disable(); 101 local_irq_disable();
101 /* Don't trace irqs off for idle */ 102 /* Don't trace irqs off for idle */
102 stop_critical_timings(); 103 stop_critical_timings();
103 pm_idle(); 104 if (cpuidle_call_idle())
105 pm_idle();
104 /* 106 /*
105 * Sanity check to ensure that pm_idle() returns 107 * Sanity check to ensure that pm_idle() returns
106 * with IRQs enabled 108 * with IRQs enabled
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index a3d0dc59067b..7a3b65107a27 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -38,6 +38,7 @@
38#include <linux/uaccess.h> 38#include <linux/uaccess.h>
39#include <linux/io.h> 39#include <linux/io.h>
40#include <linux/kdebug.h> 40#include <linux/kdebug.h>
41#include <linux/cpuidle.h>
41 42
42#include <asm/pgtable.h> 43#include <asm/pgtable.h>
43#include <asm/system.h> 44#include <asm/system.h>
@@ -109,7 +110,8 @@ void cpu_idle(void)
109 local_irq_disable(); 110 local_irq_disable();
110 /* Don't trace irqs off for idle */ 111 /* Don't trace irqs off for idle */
111 stop_critical_timings(); 112 stop_critical_timings();
112 pm_idle(); 113 if (cpuidle_idle_call())
114 pm_idle();
113 start_critical_timings(); 115 start_critical_timings();
114 } 116 }
115 tick_nohz_restart_sched_tick(); 117 tick_nohz_restart_sched_tick();
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index ca6f7ab8df33..f693e44e1bf6 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -37,6 +37,7 @@
37#include <linux/uaccess.h> 37#include <linux/uaccess.h>
38#include <linux/io.h> 38#include <linux/io.h>
39#include <linux/ftrace.h> 39#include <linux/ftrace.h>
40#include <linux/cpuidle.h>
40 41
41#include <asm/pgtable.h> 42#include <asm/pgtable.h>
42#include <asm/system.h> 43#include <asm/system.h>
@@ -136,7 +137,8 @@ void cpu_idle(void)
136 enter_idle(); 137 enter_idle();
137 /* Don't trace irqs off for idle */ 138 /* Don't trace irqs off for idle */
138 stop_critical_timings(); 139 stop_critical_timings();
139 pm_idle(); 140 if (cpuidle_idle_call())
141 pm_idle();
140 start_critical_timings(); 142 start_critical_timings();
141 143
142 /* In many cases the interrupt that ended idle 144 /* In many cases the interrupt that ended idle
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 041df0b056b2..d4c542372886 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -25,10 +25,10 @@ DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
25 25
26DEFINE_MUTEX(cpuidle_lock); 26DEFINE_MUTEX(cpuidle_lock);
27LIST_HEAD(cpuidle_detected_devices); 27LIST_HEAD(cpuidle_detected_devices);
28static void (*pm_idle_old)(void);
29 28
30static int enabled_devices; 29static int enabled_devices;
31static int off __read_mostly; 30static int off __read_mostly;
31static int initialized __read_mostly;
32 32
33int cpuidle_disabled(void) 33int cpuidle_disabled(void)
34{ 34{
@@ -56,25 +56,23 @@ static int __cpuidle_register_device(struct cpuidle_device *dev);
56 * cpuidle_idle_call - the main idle loop 56 * cpuidle_idle_call - the main idle loop
57 * 57 *
58 * NOTE: no locks or semaphores should be used here 58 * NOTE: no locks or semaphores should be used here
59 * return non-zero on failure
59 */ 60 */
60static void cpuidle_idle_call(void) 61int cpuidle_idle_call(void)
61{ 62{
62 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); 63 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
63 struct cpuidle_state *target_state; 64 struct cpuidle_state *target_state;
64 int next_state; 65 int next_state;
65 66
67 if (off)
68 return -ENODEV;
69
70 if (!initialized)
71 return -ENODEV;
72
66 /* check if the device is ready */ 73 /* check if the device is ready */
67 if (!dev || !dev->enabled) { 74 if (!dev || !dev->enabled)
68 if (pm_idle_old) 75 return -EBUSY;
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 }
78 76
79#if 0 77#if 0
80 /* shows regressions, re-enable for 2.6.29 */ 78 /* shows regressions, re-enable for 2.6.29 */
@@ -99,7 +97,7 @@ static void cpuidle_idle_call(void)
99 next_state = cpuidle_curr_governor->select(dev); 97 next_state = cpuidle_curr_governor->select(dev);
100 if (need_resched()) { 98 if (need_resched()) {
101 local_irq_enable(); 99 local_irq_enable();
102 return; 100 return 0;
103 } 101 }
104 102
105 target_state = &dev->states[next_state]; 103 target_state = &dev->states[next_state];
@@ -124,6 +122,8 @@ static void cpuidle_idle_call(void)
124 /* give the governor an opportunity to reflect on the outcome */ 122 /* give the governor an opportunity to reflect on the outcome */
125 if (cpuidle_curr_governor->reflect) 123 if (cpuidle_curr_governor->reflect)
126 cpuidle_curr_governor->reflect(dev); 124 cpuidle_curr_governor->reflect(dev);
125
126 return 0;
127} 127}
128 128
129/** 129/**
@@ -131,10 +131,10 @@ static void cpuidle_idle_call(void)
131 */ 131 */
132void cpuidle_install_idle_handler(void) 132void cpuidle_install_idle_handler(void)
133{ 133{
134 if (enabled_devices && (pm_idle != cpuidle_idle_call)) { 134 if (enabled_devices) {
135 /* Make sure all changes finished before we switch to new idle */ 135 /* Make sure all changes finished before we switch to new idle */
136 smp_wmb(); 136 smp_wmb();
137 pm_idle = cpuidle_idle_call; 137 initialized = 1;
138 } 138 }
139} 139}
140 140
@@ -143,8 +143,8 @@ void cpuidle_install_idle_handler(void)
143 */ 143 */
144void cpuidle_uninstall_idle_handler(void) 144void cpuidle_uninstall_idle_handler(void)
145{ 145{
146 if (enabled_devices && pm_idle_old && (pm_idle != pm_idle_old)) { 146 if (enabled_devices) {
147 pm_idle = pm_idle_old; 147 initialized = 0;
148 cpuidle_kick_cpus(); 148 cpuidle_kick_cpus();
149 } 149 }
150} 150}
@@ -440,8 +440,6 @@ static int __init cpuidle_init(void)
440 if (cpuidle_disabled()) 440 if (cpuidle_disabled())
441 return -ENODEV; 441 return -ENODEV;
442 442
443 pm_idle_old = pm_idle;
444
445 ret = cpuidle_add_class_sysfs(&cpu_sysdev_class); 443 ret = cpuidle_add_class_sysfs(&cpu_sysdev_class);
446 if (ret) 444 if (ret)
447 return ret; 445 return ret;
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index b89f67da919e..b51629e15cfc 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -123,6 +123,7 @@ struct cpuidle_driver {
123 123
124#ifdef CONFIG_CPU_IDLE 124#ifdef CONFIG_CPU_IDLE
125extern void disable_cpuidle(void); 125extern void disable_cpuidle(void);
126extern int cpuidle_idle_call(void);
126 127
127extern int cpuidle_register_driver(struct cpuidle_driver *drv); 128extern int cpuidle_register_driver(struct cpuidle_driver *drv);
128struct cpuidle_driver *cpuidle_get_driver(void); 129struct cpuidle_driver *cpuidle_get_driver(void);
@@ -137,6 +138,7 @@ extern void cpuidle_disable_device(struct cpuidle_device *dev);
137 138
138#else 139#else
139static inline void disable_cpuidle(void) { } 140static inline void disable_cpuidle(void) { }
141static inline int cpuidle_idle_call(void) { return -ENODEV; }
140 142
141static inline int cpuidle_register_driver(struct cpuidle_driver *drv) 143static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
142{return -ENODEV; } 144{return -ENODEV; }