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.c81
1 files changed, 52 insertions, 29 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 8ffef26ffdcf..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
@@ -134,23 +151,15 @@ int cpuidle_idle_call(void)
134 trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu); 151 trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu);
135 trace_cpu_idle_rcuidle(next_state, dev->cpu); 152 trace_cpu_idle_rcuidle(next_state, dev->cpu);
136 153
137 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);
138 159
139 trace_power_end_rcuidle(dev->cpu); 160 trace_power_end_rcuidle(dev->cpu);
140 trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); 161 trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
141 162
142 if (entered_state >= 0) {
143 /* Update cpuidle counters */
144 /* This can be moved to within driver enter routine
145 * but that results in multiple copies of same code.
146 */
147 dev->states_usage[entered_state].time +=
148 (unsigned long long)dev->last_residency;
149 dev->states_usage[entered_state].usage++;
150 } else {
151 dev->last_residency = 0;
152 }
153
154 /* give the governor an opportunity to reflect on the outcome */ 163 /* give the governor an opportunity to reflect on the outcome */
155 if (cpuidle_curr_governor->reflect) 164 if (cpuidle_curr_governor->reflect)
156 cpuidle_curr_governor->reflect(dev, entered_state); 165 cpuidle_curr_governor->reflect(dev, entered_state);
@@ -177,7 +186,7 @@ void cpuidle_uninstall_idle_handler(void)
177{ 186{
178 if (enabled_devices) { 187 if (enabled_devices) {
179 initialized = 0; 188 initialized = 0;
180 cpuidle_kick_cpus(); 189 kick_all_cpus_sync();
181 } 190 }
182} 191}
183 192
@@ -379,13 +388,25 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
379 388
380 per_cpu(cpuidle_devices, dev->cpu) = dev; 389 per_cpu(cpuidle_devices, dev->cpu) = dev;
381 list_add(&dev->device_list, &cpuidle_detected_devices); 390 list_add(&dev->device_list, &cpuidle_detected_devices);
382 if ((ret = cpuidle_add_sysfs(cpu_dev))) { 391 ret = cpuidle_add_sysfs(cpu_dev);
383 module_put(cpuidle_driver->owner); 392 if (ret)
384 return ret; 393 goto err_sysfs;
385 } 394
395 ret = cpuidle_coupled_register_device(dev);
396 if (ret)
397 goto err_coupled;
386 398
387 dev->registered = 1; 399 dev->registered = 1;
388 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;
389} 410}
390 411
391/** 412/**
@@ -438,6 +459,8 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
438 wait_for_completion(&dev->kobj_unregister); 459 wait_for_completion(&dev->kobj_unregister);
439 per_cpu(cpuidle_devices, dev->cpu) = NULL; 460 per_cpu(cpuidle_devices, dev->cpu) = NULL;
440 461
462 cpuidle_coupled_unregister_device(dev);
463
441 cpuidle_resume_and_unlock(); 464 cpuidle_resume_and_unlock();
442 465
443 module_put(cpuidle_driver->owner); 466 module_put(cpuidle_driver->owner);