Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.26-rc4 350 lines 7.7 kB view raw
1/* 2 * cpuidle.c - core cpuidle infrastructure 3 * 4 * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> 5 * Shaohua Li <shaohua.li@intel.com> 6 * Adam Belay <abelay@novell.com> 7 * 8 * This code is licenced under the GPL. 9 */ 10 11#include <linux/kernel.h> 12#include <linux/mutex.h> 13#include <linux/sched.h> 14#include <linux/notifier.h> 15#include <linux/pm_qos_params.h> 16#include <linux/cpu.h> 17#include <linux/cpuidle.h> 18#include <linux/ktime.h> 19 20#include "cpuidle.h" 21 22DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices); 23 24DEFINE_MUTEX(cpuidle_lock); 25LIST_HEAD(cpuidle_detected_devices); 26static void (*pm_idle_old)(void); 27 28static int enabled_devices; 29 30#if defined(CONFIG_ARCH_HAS_CPU_IDLE_WAIT) 31static void cpuidle_kick_cpus(void) 32{ 33 cpu_idle_wait(); 34} 35#elif defined(CONFIG_SMP) 36# error "Arch needs cpu_idle_wait() equivalent here" 37#else /* !CONFIG_ARCH_HAS_CPU_IDLE_WAIT && !CONFIG_SMP */ 38static void cpuidle_kick_cpus(void) {} 39#endif 40 41/** 42 * cpuidle_idle_call - the main idle loop 43 * 44 * NOTE: no locks or semaphores should be used here 45 */ 46static void cpuidle_idle_call(void) 47{ 48 struct cpuidle_device *dev = __get_cpu_var(cpuidle_devices); 49 struct cpuidle_state *target_state; 50 int next_state; 51 52 /* check if the device is ready */ 53 if (!dev || !dev->enabled) { 54 if (pm_idle_old) 55 pm_idle_old(); 56 else 57 local_irq_enable(); 58 return; 59 } 60 61 /* ask the governor for the next state */ 62 next_state = cpuidle_curr_governor->select(dev); 63 if (need_resched()) 64 return; 65 target_state = &dev->states[next_state]; 66 67 /* enter the state and update stats */ 68 dev->last_residency = target_state->enter(dev, target_state); 69 dev->last_state = target_state; 70 target_state->time += (unsigned long long)dev->last_residency; 71 target_state->usage++; 72 73 /* give the governor an opportunity to reflect on the outcome */ 74 if (cpuidle_curr_governor->reflect) 75 cpuidle_curr_governor->reflect(dev); 76} 77 78/** 79 * cpuidle_install_idle_handler - installs the cpuidle idle loop handler 80 */ 81void cpuidle_install_idle_handler(void) 82{ 83 if (enabled_devices && (pm_idle != cpuidle_idle_call)) { 84 /* Make sure all changes finished before we switch to new idle */ 85 smp_wmb(); 86 pm_idle = cpuidle_idle_call; 87 } 88} 89 90/** 91 * cpuidle_uninstall_idle_handler - uninstalls the cpuidle idle loop handler 92 */ 93void cpuidle_uninstall_idle_handler(void) 94{ 95 if (enabled_devices && (pm_idle != pm_idle_old)) { 96 pm_idle = pm_idle_old; 97 cpuidle_kick_cpus(); 98 } 99} 100 101/** 102 * cpuidle_pause_and_lock - temporarily disables CPUIDLE 103 */ 104void cpuidle_pause_and_lock(void) 105{ 106 mutex_lock(&cpuidle_lock); 107 cpuidle_uninstall_idle_handler(); 108} 109 110EXPORT_SYMBOL_GPL(cpuidle_pause_and_lock); 111 112/** 113 * cpuidle_resume_and_unlock - resumes CPUIDLE operation 114 */ 115void cpuidle_resume_and_unlock(void) 116{ 117 cpuidle_install_idle_handler(); 118 mutex_unlock(&cpuidle_lock); 119} 120 121EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); 122 123/** 124 * cpuidle_enable_device - enables idle PM for a CPU 125 * @dev: the CPU 126 * 127 * This function must be called between cpuidle_pause_and_lock and 128 * cpuidle_resume_and_unlock when used externally. 129 */ 130int cpuidle_enable_device(struct cpuidle_device *dev) 131{ 132 int ret, i; 133 134 if (dev->enabled) 135 return 0; 136 if (!cpuidle_curr_driver || !cpuidle_curr_governor) 137 return -EIO; 138 if (!dev->state_count) 139 return -EINVAL; 140 141 if ((ret = cpuidle_add_state_sysfs(dev))) 142 return ret; 143 144 if (cpuidle_curr_governor->enable && 145 (ret = cpuidle_curr_governor->enable(dev))) 146 goto fail_sysfs; 147 148 for (i = 0; i < dev->state_count; i++) { 149 dev->states[i].usage = 0; 150 dev->states[i].time = 0; 151 } 152 dev->last_residency = 0; 153 dev->last_state = NULL; 154 155 smp_wmb(); 156 157 dev->enabled = 1; 158 159 enabled_devices++; 160 return 0; 161 162fail_sysfs: 163 cpuidle_remove_state_sysfs(dev); 164 165 return ret; 166} 167 168EXPORT_SYMBOL_GPL(cpuidle_enable_device); 169 170/** 171 * cpuidle_disable_device - disables idle PM for a CPU 172 * @dev: the CPU 173 * 174 * This function must be called between cpuidle_pause_and_lock and 175 * cpuidle_resume_and_unlock when used externally. 176 */ 177void cpuidle_disable_device(struct cpuidle_device *dev) 178{ 179 if (!dev->enabled) 180 return; 181 if (!cpuidle_curr_driver || !cpuidle_curr_governor) 182 return; 183 184 dev->enabled = 0; 185 186 if (cpuidle_curr_governor->disable) 187 cpuidle_curr_governor->disable(dev); 188 189 cpuidle_remove_state_sysfs(dev); 190 enabled_devices--; 191} 192 193EXPORT_SYMBOL_GPL(cpuidle_disable_device); 194 195#ifdef CONFIG_ARCH_HAS_CPU_RELAX 196static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) 197{ 198 ktime_t t1, t2; 199 s64 diff; 200 int ret; 201 202 t1 = ktime_get(); 203 local_irq_enable(); 204 while (!need_resched()) 205 cpu_relax(); 206 207 t2 = ktime_get(); 208 diff = ktime_to_us(ktime_sub(t2, t1)); 209 if (diff > INT_MAX) 210 diff = INT_MAX; 211 212 ret = (int) diff; 213 return ret; 214} 215 216static void poll_idle_init(struct cpuidle_device *dev) 217{ 218 struct cpuidle_state *state = &dev->states[0]; 219 220 cpuidle_set_statedata(state, NULL); 221 222 snprintf(state->name, CPUIDLE_NAME_LEN, "C0"); 223 snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); 224 state->exit_latency = 0; 225 state->target_residency = 0; 226 state->power_usage = -1; 227 state->flags = CPUIDLE_FLAG_POLL; 228 state->enter = poll_idle; 229} 230#else 231static void poll_idle_init(struct cpuidle_device *dev) {} 232#endif /* CONFIG_ARCH_HAS_CPU_RELAX */ 233 234/** 235 * cpuidle_register_device - registers a CPU's idle PM feature 236 * @dev: the cpu 237 */ 238int cpuidle_register_device(struct cpuidle_device *dev) 239{ 240 int ret; 241 struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); 242 243 if (!sys_dev) 244 return -EINVAL; 245 if (!try_module_get(cpuidle_curr_driver->owner)) 246 return -EINVAL; 247 248 init_completion(&dev->kobj_unregister); 249 250 mutex_lock(&cpuidle_lock); 251 252 poll_idle_init(dev); 253 254 per_cpu(cpuidle_devices, dev->cpu) = dev; 255 list_add(&dev->device_list, &cpuidle_detected_devices); 256 if ((ret = cpuidle_add_sysfs(sys_dev))) { 257 mutex_unlock(&cpuidle_lock); 258 module_put(cpuidle_curr_driver->owner); 259 return ret; 260 } 261 262 cpuidle_enable_device(dev); 263 cpuidle_install_idle_handler(); 264 265 mutex_unlock(&cpuidle_lock); 266 267 return 0; 268 269} 270 271EXPORT_SYMBOL_GPL(cpuidle_register_device); 272 273/** 274 * cpuidle_unregister_device - unregisters a CPU's idle PM feature 275 * @dev: the cpu 276 */ 277void cpuidle_unregister_device(struct cpuidle_device *dev) 278{ 279 struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); 280 281 cpuidle_pause_and_lock(); 282 283 cpuidle_disable_device(dev); 284 285 cpuidle_remove_sysfs(sys_dev); 286 list_del(&dev->device_list); 287 wait_for_completion(&dev->kobj_unregister); 288 per_cpu(cpuidle_devices, dev->cpu) = NULL; 289 290 cpuidle_resume_and_unlock(); 291 292 module_put(cpuidle_curr_driver->owner); 293} 294 295EXPORT_SYMBOL_GPL(cpuidle_unregister_device); 296 297#ifdef CONFIG_SMP 298 299static void smp_callback(void *v) 300{ 301 /* we already woke the CPU up, nothing more to do */ 302} 303 304/* 305 * This function gets called when a part of the kernel has a new latency 306 * requirement. This means we need to get all processors out of their C-state, 307 * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that 308 * wakes them all right up. 309 */ 310static int cpuidle_latency_notify(struct notifier_block *b, 311 unsigned long l, void *v) 312{ 313 smp_call_function(smp_callback, NULL, 0, 1); 314 return NOTIFY_OK; 315} 316 317static struct notifier_block cpuidle_latency_notifier = { 318 .notifier_call = cpuidle_latency_notify, 319}; 320 321static inline void latency_notifier_init(struct notifier_block *n) 322{ 323 pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY, n); 324} 325 326#else /* CONFIG_SMP */ 327 328#define latency_notifier_init(x) do { } while (0) 329 330#endif /* CONFIG_SMP */ 331 332/** 333 * cpuidle_init - core initializer 334 */ 335static int __init cpuidle_init(void) 336{ 337 int ret; 338 339 pm_idle_old = pm_idle; 340 341 ret = cpuidle_add_class_sysfs(&cpu_sysdev_class); 342 if (ret) 343 return ret; 344 345 latency_notifier_init(&cpuidle_latency_notifier); 346 347 return 0; 348} 349 350core_initcall(cpuidle_init);