aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle/cpuidle.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cpuidle/cpuidle.c')
-rw-r--r--drivers/cpuidle/cpuidle.c98
1 files changed, 58 insertions, 40 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 2f0083a51a9a..bb4e827434ce 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -40,17 +40,6 @@ void disable_cpuidle(void)
40 off = 1; 40 off = 1;
41} 41}
42 42
43#if defined(CONFIG_ARCH_HAS_CPU_IDLE_WAIT)
44static void cpuidle_kick_cpus(void)
45{
46 cpu_idle_wait();
47}
48#elif defined(CONFIG_SMP)
49# error "Arch needs cpu_idle_wait() equivalent here"
50#else /* !CONFIG_ARCH_HAS_CPU_IDLE_WAIT && !CONFIG_SMP */
51static void cpuidle_kick_cpus(void) {}
52#endif
53
54static int __cpuidle_register_device(struct cpuidle_device *dev); 43static int __cpuidle_register_device(struct cpuidle_device *dev);
55 44
56static inline int cpuidle_enter(struct cpuidle_device *dev, 45static inline int cpuidle_enter(struct cpuidle_device *dev,
@@ -103,6 +92,34 @@ int cpuidle_play_dead(void)
103} 92}
104 93
105/** 94/**
95 * cpuidle_enter_state - enter the state and update stats
96 * @dev: cpuidle device for this cpu
97 * @drv: cpuidle driver for this cpu
98 * @next_state: index into drv->states of the state to enter
99 */
100int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
101 int next_state)
102{
103 int entered_state;
104
105 entered_state = cpuidle_enter_ops(dev, drv, next_state);
106
107 if (entered_state >= 0) {
108 /* Update cpuidle counters */
109 /* This can be moved to within driver enter routine
110 * but that results in multiple copies of same code.
111 */
112 dev->states_usage[entered_state].time +=
113 (unsigned long long)dev->last_residency;
114 dev->states_usage[entered_state].usage++;
115 } else {
116 dev->last_residency = 0;
117 }
118
119 return entered_state;
120}
121
122/**
106 * cpuidle_idle_call - the main idle loop 123 * cpuidle_idle_call - the main idle loop
107 * 124 *
108 * NOTE: no locks or semaphores should be used here 125 * NOTE: no locks or semaphores should be used here
@@ -124,15 +141,6 @@ int cpuidle_idle_call(void)
124 if (!dev || !dev->enabled) 141 if (!dev || !dev->enabled)
125 return -EBUSY; 142 return -EBUSY;
126 143
127#if 0
128 /* shows regressions, re-enable for 2.6.29 */
129 /*
130 * run any timers that can be run now, at this point
131 * before calculating the idle duration etc.
132 */
133 hrtimer_peek_ahead_timers();
134#endif
135
136 /* ask the governor for the next state */ 144 /* ask the governor for the next state */
137 next_state = cpuidle_curr_governor->select(drv, dev); 145 next_state = cpuidle_curr_governor->select(drv, dev);
138 if (need_resched()) { 146 if (need_resched()) {
@@ -143,23 +151,15 @@ int cpuidle_idle_call(void)
143 trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu); 151 trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu);
144 trace_cpu_idle_rcuidle(next_state, dev->cpu); 152 trace_cpu_idle_rcuidle(next_state, dev->cpu);
145 153
146 entered_state = cpuidle_enter_ops(dev, drv, next_state); 154 if (cpuidle_state_is_coupled(dev, drv, next_state))
155 entered_state = cpuidle_enter_state_coupled(dev, drv,
156 next_state);
157 else
158 entered_state = cpuidle_enter_state(dev, drv, next_state);
147 159
148 trace_power_end_rcuidle(dev->cpu); 160 trace_power_end_rcuidle(dev->cpu);
149 trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); 161 trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
150 162
151 if (entered_state >= 0) {
152 /* Update cpuidle counters */
153 /* This can be moved to within driver enter routine
154 * but that results in multiple copies of same code.
155 */
156 dev->states_usage[entered_state].time +=
157 (unsigned long long)dev->last_residency;
158 dev->states_usage[entered_state].usage++;
159 } else {
160 dev->last_residency = 0;
161 }
162
163 /* give the governor an opportunity to reflect on the outcome */ 163 /* give the governor an opportunity to reflect on the outcome */
164 if (cpuidle_curr_governor->reflect) 164 if (cpuidle_curr_governor->reflect)
165 cpuidle_curr_governor->reflect(dev, entered_state); 165 cpuidle_curr_governor->reflect(dev, entered_state);
@@ -186,7 +186,7 @@ void cpuidle_uninstall_idle_handler(void)
186{ 186{
187 if (enabled_devices) { 187 if (enabled_devices) {
188 initialized = 0; 188 initialized = 0;
189 cpuidle_kick_cpus(); 189 kick_all_cpus_sync();
190 } 190 }
191} 191}
192 192
@@ -294,6 +294,9 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
294 int ret, i; 294 int ret, i;
295 struct cpuidle_driver *drv = cpuidle_get_driver(); 295 struct cpuidle_driver *drv = cpuidle_get_driver();
296 296
297 if (!dev)
298 return -EINVAL;
299
297 if (dev->enabled) 300 if (dev->enabled)
298 return 0; 301 return 0;
299 if (!drv || !cpuidle_curr_governor) 302 if (!drv || !cpuidle_curr_governor)
@@ -378,8 +381,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
378 struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); 381 struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu);
379 struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); 382 struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
380 383
381 if (!dev)
382 return -EINVAL;
383 if (!try_module_get(cpuidle_driver->owner)) 384 if (!try_module_get(cpuidle_driver->owner))
384 return -EINVAL; 385 return -EINVAL;
385 386
@@ -387,13 +388,25 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
387 388
388 per_cpu(cpuidle_devices, dev->cpu) = dev; 389 per_cpu(cpuidle_devices, dev->cpu) = dev;
389 list_add(&dev->device_list, &cpuidle_detected_devices); 390 list_add(&dev->device_list, &cpuidle_detected_devices);
390 if ((ret = cpuidle_add_sysfs(cpu_dev))) { 391 ret = cpuidle_add_sysfs(cpu_dev);
391 module_put(cpuidle_driver->owner); 392 if (ret)
392 return ret; 393 goto err_sysfs;
393 } 394
395 ret = cpuidle_coupled_register_device(dev);
396 if (ret)
397 goto err_coupled;
394 398
395 dev->registered = 1; 399 dev->registered = 1;
396 return 0; 400 return 0;
401
402err_coupled:
403 cpuidle_remove_sysfs(cpu_dev);
404 wait_for_completion(&dev->kobj_unregister);
405err_sysfs:
406 list_del(&dev->device_list);
407 per_cpu(cpuidle_devices, dev->cpu) = NULL;
408 module_put(cpuidle_driver->owner);
409 return ret;
397} 410}
398 411
399/** 412/**
@@ -404,6 +417,9 @@ int cpuidle_register_device(struct cpuidle_device *dev)
404{ 417{
405 int ret; 418 int ret;
406 419
420 if (!dev)
421 return -EINVAL;
422
407 mutex_lock(&cpuidle_lock); 423 mutex_lock(&cpuidle_lock);
408 424
409 if ((ret = __cpuidle_register_device(dev))) { 425 if ((ret = __cpuidle_register_device(dev))) {
@@ -443,6 +459,8 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
443 wait_for_completion(&dev->kobj_unregister); 459 wait_for_completion(&dev->kobj_unregister);
444 per_cpu(cpuidle_devices, dev->cpu) = NULL; 460 per_cpu(cpuidle_devices, dev->cpu) = NULL;
445 461
462 cpuidle_coupled_unregister_device(dev);
463
446 cpuidle_resume_and_unlock(); 464 cpuidle_resume_and_unlock();
447 465
448 module_put(cpuidle_driver->owner); 466 module_put(cpuidle_driver->owner);