diff options
| -rw-r--r-- | Documentation/cpuidle/governor.txt | 1 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/cpuidle.c | 6 | ||||
| -rw-r--r-- | drivers/cpuidle/coupled.c | 2 | ||||
| -rw-r--r-- | drivers/cpuidle/cpuidle.c | 78 | ||||
| -rw-r--r-- | drivers/cpuidle/driver.c | 67 | ||||
| -rw-r--r-- | drivers/cpuidle/governor.c | 43 | ||||
| -rw-r--r-- | drivers/cpuidle/sysfs.c | 7 | ||||
| -rw-r--r-- | drivers/idle/intel_idle.c | 2 | ||||
| -rw-r--r-- | include/linux/cpuidle.h | 8 |
9 files changed, 76 insertions, 138 deletions
diff --git a/Documentation/cpuidle/governor.txt b/Documentation/cpuidle/governor.txt index 12c6bd50c9f6..d9020f5e847b 100644 --- a/Documentation/cpuidle/governor.txt +++ b/Documentation/cpuidle/governor.txt | |||
| @@ -25,5 +25,4 @@ kernel configuration and platform will be selected by cpuidle. | |||
| 25 | 25 | ||
| 26 | Interfaces: | 26 | Interfaces: |
| 27 | extern int cpuidle_register_governor(struct cpuidle_governor *gov); | 27 | extern int cpuidle_register_governor(struct cpuidle_governor *gov); |
| 28 | extern void cpuidle_unregister_governor(struct cpuidle_governor *gov); | ||
| 29 | struct cpuidle_governor | 28 | struct cpuidle_governor |
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 1bde6ad07d93..ddbfe8709fe7 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c | |||
| @@ -193,7 +193,7 @@ static void __init exynos5_core_down_clk(void) | |||
| 193 | __raw_writel(tmp, EXYNOS5_PWR_CTRL2); | 193 | __raw_writel(tmp, EXYNOS5_PWR_CTRL2); |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | static int __init exynos_cpuidle_probe(struct platform_device *pdev) | 196 | static int exynos_cpuidle_probe(struct platform_device *pdev) |
| 197 | { | 197 | { |
| 198 | int cpu_id, ret; | 198 | int cpu_id, ret; |
| 199 | struct cpuidle_device *device; | 199 | struct cpuidle_device *device; |
| @@ -206,7 +206,7 @@ static int __init exynos_cpuidle_probe(struct platform_device *pdev) | |||
| 206 | 206 | ||
| 207 | ret = cpuidle_register_driver(&exynos4_idle_driver); | 207 | ret = cpuidle_register_driver(&exynos4_idle_driver); |
| 208 | if (ret) { | 208 | if (ret) { |
| 209 | printk(KERN_ERR "CPUidle failed to register driver\n"); | 209 | dev_err(&pdev->dev, "failed to register cpuidle driver\n"); |
| 210 | return ret; | 210 | return ret; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| @@ -220,7 +220,7 @@ static int __init exynos_cpuidle_probe(struct platform_device *pdev) | |||
| 220 | 220 | ||
| 221 | ret = cpuidle_register_device(device); | 221 | ret = cpuidle_register_device(device); |
| 222 | if (ret) { | 222 | if (ret) { |
| 223 | printk(KERN_ERR "CPUidle register device failed\n"); | 223 | dev_err(&pdev->dev, "failed to register cpuidle device\n"); |
| 224 | return ret; | 224 | return ret; |
| 225 | } | 225 | } |
| 226 | } | 226 | } |
diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c index f8a86364c6b6..e952936418d0 100644 --- a/drivers/cpuidle/coupled.c +++ b/drivers/cpuidle/coupled.c | |||
| @@ -147,7 +147,7 @@ static cpumask_t cpuidle_coupled_poked; | |||
| 147 | * has returned from this function, the barrier is immediately available for | 147 | * has returned from this function, the barrier is immediately available for |
| 148 | * reuse. | 148 | * reuse. |
| 149 | * | 149 | * |
| 150 | * The atomic variable a must be initialized to 0 before any cpu calls | 150 | * The atomic variable must be initialized to 0 before any cpu calls |
| 151 | * this function, will be reset to 0 before any cpu returns from this function. | 151 | * this function, will be reset to 0 before any cpu returns from this function. |
| 152 | * | 152 | * |
| 153 | * Must only be called from within a coupled idle state handler | 153 | * Must only be called from within a coupled idle state handler |
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index d75040ddd2b3..2a991e468f78 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
| @@ -118,11 +118,9 @@ int cpuidle_idle_call(void) | |||
| 118 | struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); | 118 | struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); |
| 119 | struct cpuidle_driver *drv; | 119 | struct cpuidle_driver *drv; |
| 120 | int next_state, entered_state; | 120 | int next_state, entered_state; |
| 121 | bool broadcast; | ||
| 121 | 122 | ||
| 122 | if (off) | 123 | if (off || !initialized) |
| 123 | return -ENODEV; | ||
| 124 | |||
| 125 | if (!initialized) | ||
| 126 | return -ENODEV; | 124 | return -ENODEV; |
| 127 | 125 | ||
| 128 | /* check if the device is ready */ | 126 | /* check if the device is ready */ |
| @@ -144,9 +142,10 @@ int cpuidle_idle_call(void) | |||
| 144 | 142 | ||
| 145 | trace_cpu_idle_rcuidle(next_state, dev->cpu); | 143 | trace_cpu_idle_rcuidle(next_state, dev->cpu); |
| 146 | 144 | ||
| 147 | if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP) | 145 | broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP); |
| 148 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, | 146 | |
| 149 | &dev->cpu); | 147 | if (broadcast) |
| 148 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu); | ||
| 150 | 149 | ||
| 151 | if (cpuidle_state_is_coupled(dev, drv, next_state)) | 150 | if (cpuidle_state_is_coupled(dev, drv, next_state)) |
| 152 | entered_state = cpuidle_enter_state_coupled(dev, drv, | 151 | entered_state = cpuidle_enter_state_coupled(dev, drv, |
| @@ -154,9 +153,8 @@ int cpuidle_idle_call(void) | |||
| 154 | else | 153 | else |
| 155 | entered_state = cpuidle_enter_state(dev, drv, next_state); | 154 | entered_state = cpuidle_enter_state(dev, drv, next_state); |
| 156 | 155 | ||
| 157 | if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP) | 156 | if (broadcast) |
| 158 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, | 157 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); |
| 159 | &dev->cpu); | ||
| 160 | 158 | ||
| 161 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); | 159 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); |
| 162 | 160 | ||
| @@ -228,45 +226,6 @@ void cpuidle_resume(void) | |||
| 228 | mutex_unlock(&cpuidle_lock); | 226 | mutex_unlock(&cpuidle_lock); |
| 229 | } | 227 | } |
| 230 | 228 | ||
| 231 | #ifdef CONFIG_ARCH_HAS_CPU_RELAX | ||
| 232 | static int poll_idle(struct cpuidle_device *dev, | ||
| 233 | struct cpuidle_driver *drv, int index) | ||
| 234 | { | ||
| 235 | ktime_t t1, t2; | ||
| 236 | s64 diff; | ||
| 237 | |||
| 238 | t1 = ktime_get(); | ||
| 239 | local_irq_enable(); | ||
| 240 | while (!need_resched()) | ||
| 241 | cpu_relax(); | ||
| 242 | |||
| 243 | t2 = ktime_get(); | ||
| 244 | diff = ktime_to_us(ktime_sub(t2, t1)); | ||
| 245 | if (diff > INT_MAX) | ||
| 246 | diff = INT_MAX; | ||
| 247 | |||
| 248 | dev->last_residency = (int) diff; | ||
| 249 | |||
| 250 | return index; | ||
| 251 | } | ||
| 252 | |||
| 253 | static void poll_idle_init(struct cpuidle_driver *drv) | ||
| 254 | { | ||
| 255 | struct cpuidle_state *state = &drv->states[0]; | ||
| 256 | |||
| 257 | snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); | ||
| 258 | snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); | ||
| 259 | state->exit_latency = 0; | ||
| 260 | state->target_residency = 0; | ||
| 261 | state->power_usage = -1; | ||
| 262 | state->flags = 0; | ||
| 263 | state->enter = poll_idle; | ||
| 264 | state->disabled = false; | ||
| 265 | } | ||
| 266 | #else | ||
| 267 | static void poll_idle_init(struct cpuidle_driver *drv) {} | ||
| 268 | #endif /* CONFIG_ARCH_HAS_CPU_RELAX */ | ||
| 269 | |||
| 270 | /** | 229 | /** |
| 271 | * cpuidle_enable_device - enables idle PM for a CPU | 230 | * cpuidle_enable_device - enables idle PM for a CPU |
| 272 | * @dev: the CPU | 231 | * @dev: the CPU |
| @@ -296,8 +255,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev) | |||
| 296 | if (!dev->state_count) | 255 | if (!dev->state_count) |
| 297 | dev->state_count = drv->state_count; | 256 | dev->state_count = drv->state_count; |
| 298 | 257 | ||
| 299 | poll_idle_init(drv); | ||
| 300 | |||
| 301 | ret = cpuidle_add_device_sysfs(dev); | 258 | ret = cpuidle_add_device_sysfs(dev); |
| 302 | if (ret) | 259 | if (ret) |
| 303 | return ret; | 260 | return ret; |
| @@ -358,12 +315,10 @@ static void __cpuidle_unregister_device(struct cpuidle_device *dev) | |||
| 358 | module_put(drv->owner); | 315 | module_put(drv->owner); |
| 359 | } | 316 | } |
| 360 | 317 | ||
| 361 | static int __cpuidle_device_init(struct cpuidle_device *dev) | 318 | static void __cpuidle_device_init(struct cpuidle_device *dev) |
| 362 | { | 319 | { |
| 363 | memset(dev->states_usage, 0, sizeof(dev->states_usage)); | 320 | memset(dev->states_usage, 0, sizeof(dev->states_usage)); |
| 364 | dev->last_residency = 0; | 321 | dev->last_residency = 0; |
| 365 | |||
| 366 | return 0; | ||
| 367 | } | 322 | } |
| 368 | 323 | ||
| 369 | /** | 324 | /** |
| @@ -385,13 +340,12 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) | |||
| 385 | list_add(&dev->device_list, &cpuidle_detected_devices); | 340 | list_add(&dev->device_list, &cpuidle_detected_devices); |
| 386 | 341 | ||
| 387 | ret = cpuidle_coupled_register_device(dev); | 342 | ret = cpuidle_coupled_register_device(dev); |
| 388 | if (ret) { | 343 | if (ret) |
| 389 | __cpuidle_unregister_device(dev); | 344 | __cpuidle_unregister_device(dev); |
| 390 | return ret; | 345 | else |
| 391 | } | 346 | dev->registered = 1; |
| 392 | 347 | ||
| 393 | dev->registered = 1; | 348 | return ret; |
| 394 | return 0; | ||
| 395 | } | 349 | } |
| 396 | 350 | ||
| 397 | /** | 351 | /** |
| @@ -410,9 +364,7 @@ int cpuidle_register_device(struct cpuidle_device *dev) | |||
| 410 | if (dev->registered) | 364 | if (dev->registered) |
| 411 | goto out_unlock; | 365 | goto out_unlock; |
| 412 | 366 | ||
| 413 | ret = __cpuidle_device_init(dev); | 367 | __cpuidle_device_init(dev); |
| 414 | if (ret) | ||
| 415 | goto out_unlock; | ||
| 416 | 368 | ||
| 417 | ret = __cpuidle_register_device(dev); | 369 | ret = __cpuidle_register_device(dev); |
| 418 | if (ret) | 370 | if (ret) |
| @@ -516,7 +468,7 @@ int cpuidle_register(struct cpuidle_driver *drv, | |||
| 516 | 468 | ||
| 517 | #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED | 469 | #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED |
| 518 | /* | 470 | /* |
| 519 | * On multiplatform for ARM, the coupled idle states could | 471 | * On multiplatform for ARM, the coupled idle states could be |
| 520 | * enabled in the kernel even if the cpuidle driver does not | 472 | * enabled in the kernel even if the cpuidle driver does not |
| 521 | * use it. Note, coupled_cpus is a struct copy. | 473 | * use it. Note, coupled_cpus is a struct copy. |
| 522 | */ | 474 | */ |
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 6e11701f0fca..06dbe7c86199 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | #include <linux/mutex.h> | 11 | #include <linux/mutex.h> |
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/sched.h> | ||
| 13 | #include <linux/cpuidle.h> | 14 | #include <linux/cpuidle.h> |
| 14 | #include <linux/cpumask.h> | 15 | #include <linux/cpumask.h> |
| 15 | #include <linux/clockchips.h> | 16 | #include <linux/clockchips.h> |
| @@ -56,7 +57,7 @@ static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv) | |||
| 56 | } | 57 | } |
| 57 | 58 | ||
| 58 | /** | 59 | /** |
| 59 | * __cpuidle_set_driver - set per CPU driver variables the the given driver. | 60 | * __cpuidle_set_driver - set per CPU driver variables for the given driver. |
| 60 | * @drv: a valid pointer to a struct cpuidle_driver | 61 | * @drv: a valid pointer to a struct cpuidle_driver |
| 61 | * | 62 | * |
| 62 | * For each CPU in the driver's cpumask, unset the registered driver per CPU | 63 | * For each CPU in the driver's cpumask, unset the registered driver per CPU |
| @@ -132,7 +133,7 @@ static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv) | |||
| 132 | * cpuidle_setup_broadcast_timer - enable/disable the broadcast timer | 133 | * cpuidle_setup_broadcast_timer - enable/disable the broadcast timer |
| 133 | * @arg: a void pointer used to match the SMP cross call API | 134 | * @arg: a void pointer used to match the SMP cross call API |
| 134 | * | 135 | * |
| 135 | * @arg is used as a value of type 'long' with on of the two values: | 136 | * @arg is used as a value of type 'long' with one of the two values: |
| 136 | * - CLOCK_EVT_NOTIFY_BROADCAST_ON | 137 | * - CLOCK_EVT_NOTIFY_BROADCAST_ON |
| 137 | * - CLOCK_EVT_NOTIFY_BROADCAST_OFF | 138 | * - CLOCK_EVT_NOTIFY_BROADCAST_OFF |
| 138 | * | 139 | * |
| @@ -149,10 +150,8 @@ static void cpuidle_setup_broadcast_timer(void *arg) | |||
| 149 | /** | 150 | /** |
| 150 | * __cpuidle_driver_init - initialize the driver's internal data | 151 | * __cpuidle_driver_init - initialize the driver's internal data |
| 151 | * @drv: a valid pointer to a struct cpuidle_driver | 152 | * @drv: a valid pointer to a struct cpuidle_driver |
| 152 | * | ||
| 153 | * Returns 0 on success, a negative error code otherwise. | ||
| 154 | */ | 153 | */ |
| 155 | static int __cpuidle_driver_init(struct cpuidle_driver *drv) | 154 | static void __cpuidle_driver_init(struct cpuidle_driver *drv) |
| 156 | { | 155 | { |
| 157 | int i; | 156 | int i; |
| 158 | 157 | ||
| @@ -169,20 +168,55 @@ static int __cpuidle_driver_init(struct cpuidle_driver *drv) | |||
| 169 | /* | 168 | /* |
| 170 | * Look for the timer stop flag in the different states, so that we know | 169 | * Look for the timer stop flag in the different states, so that we know |
| 171 | * if the broadcast timer has to be set up. The loop is in the reverse | 170 | * if the broadcast timer has to be set up. The loop is in the reverse |
| 172 | * order, because usually on of the the deeper states has this flag set. | 171 | * order, because usually one of the deeper states have this flag set. |
| 173 | */ | 172 | */ |
| 174 | for (i = drv->state_count - 1; i >= 0 ; i--) { | 173 | for (i = drv->state_count - 1; i >= 0 ; i--) { |
| 174 | if (drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP) { | ||
| 175 | drv->bctimer = 1; | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | } | ||
| 175 | 180 | ||
| 176 | if (!(drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP)) | 181 | #ifdef CONFIG_ARCH_HAS_CPU_RELAX |
| 177 | continue; | 182 | static int poll_idle(struct cpuidle_device *dev, |
| 183 | struct cpuidle_driver *drv, int index) | ||
| 184 | { | ||
| 185 | ktime_t t1, t2; | ||
| 186 | s64 diff; | ||
| 178 | 187 | ||
| 179 | drv->bctimer = 1; | 188 | t1 = ktime_get(); |
| 180 | break; | 189 | local_irq_enable(); |
| 181 | } | 190 | while (!need_resched()) |
| 191 | cpu_relax(); | ||
| 182 | 192 | ||
| 183 | return 0; | 193 | t2 = ktime_get(); |
| 194 | diff = ktime_to_us(ktime_sub(t2, t1)); | ||
| 195 | if (diff > INT_MAX) | ||
| 196 | diff = INT_MAX; | ||
| 197 | |||
| 198 | dev->last_residency = (int) diff; | ||
| 199 | |||
| 200 | return index; | ||
| 184 | } | 201 | } |
| 185 | 202 | ||
| 203 | static void poll_idle_init(struct cpuidle_driver *drv) | ||
| 204 | { | ||
| 205 | struct cpuidle_state *state = &drv->states[0]; | ||
| 206 | |||
| 207 | snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); | ||
| 208 | snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); | ||
| 209 | state->exit_latency = 0; | ||
| 210 | state->target_residency = 0; | ||
| 211 | state->power_usage = -1; | ||
| 212 | state->flags = 0; | ||
| 213 | state->enter = poll_idle; | ||
| 214 | state->disabled = false; | ||
| 215 | } | ||
| 216 | #else | ||
| 217 | static void poll_idle_init(struct cpuidle_driver *drv) {} | ||
| 218 | #endif /* !CONFIG_ARCH_HAS_CPU_RELAX */ | ||
| 219 | |||
| 186 | /** | 220 | /** |
| 187 | * __cpuidle_register_driver: register the driver | 221 | * __cpuidle_register_driver: register the driver |
| 188 | * @drv: a valid pointer to a struct cpuidle_driver | 222 | * @drv: a valid pointer to a struct cpuidle_driver |
| @@ -206,9 +240,7 @@ static int __cpuidle_register_driver(struct cpuidle_driver *drv) | |||
| 206 | if (cpuidle_disabled()) | 240 | if (cpuidle_disabled()) |
| 207 | return -ENODEV; | 241 | return -ENODEV; |
| 208 | 242 | ||
| 209 | ret = __cpuidle_driver_init(drv); | 243 | __cpuidle_driver_init(drv); |
| 210 | if (ret) | ||
| 211 | return ret; | ||
| 212 | 244 | ||
| 213 | ret = __cpuidle_set_driver(drv); | 245 | ret = __cpuidle_set_driver(drv); |
| 214 | if (ret) | 246 | if (ret) |
| @@ -218,6 +250,8 @@ static int __cpuidle_register_driver(struct cpuidle_driver *drv) | |||
| 218 | on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer, | 250 | on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer, |
| 219 | (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1); | 251 | (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1); |
| 220 | 252 | ||
| 253 | poll_idle_init(drv); | ||
| 254 | |||
| 221 | return 0; | 255 | return 0; |
| 222 | } | 256 | } |
| 223 | 257 | ||
| @@ -346,10 +380,11 @@ struct cpuidle_driver *cpuidle_driver_ref(void) | |||
| 346 | */ | 380 | */ |
| 347 | void cpuidle_driver_unref(void) | 381 | void cpuidle_driver_unref(void) |
| 348 | { | 382 | { |
| 349 | struct cpuidle_driver *drv = cpuidle_get_driver(); | 383 | struct cpuidle_driver *drv; |
| 350 | 384 | ||
| 351 | spin_lock(&cpuidle_driver_lock); | 385 | spin_lock(&cpuidle_driver_lock); |
| 352 | 386 | ||
| 387 | drv = cpuidle_get_driver(); | ||
| 353 | if (drv && !WARN_ON(drv->refcnt <= 0)) | 388 | if (drv && !WARN_ON(drv->refcnt <= 0)) |
| 354 | drv->refcnt--; | 389 | drv->refcnt--; |
| 355 | 390 | ||
diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c index ea2f8e7aa24a..ca89412f5122 100644 --- a/drivers/cpuidle/governor.c +++ b/drivers/cpuidle/governor.c | |||
| @@ -96,46 +96,3 @@ int cpuidle_register_governor(struct cpuidle_governor *gov) | |||
| 96 | 96 | ||
| 97 | return ret; | 97 | return ret; |
| 98 | } | 98 | } |
| 99 | |||
| 100 | /** | ||
| 101 | * cpuidle_replace_governor - find a replacement governor | ||
| 102 | * @exclude_rating: the rating that will be skipped while looking for | ||
| 103 | * new governor. | ||
| 104 | */ | ||
| 105 | static struct cpuidle_governor *cpuidle_replace_governor(int exclude_rating) | ||
| 106 | { | ||
| 107 | struct cpuidle_governor *gov; | ||
| 108 | struct cpuidle_governor *ret_gov = NULL; | ||
| 109 | unsigned int max_rating = 0; | ||
| 110 | |||
| 111 | list_for_each_entry(gov, &cpuidle_governors, governor_list) { | ||
| 112 | if (gov->rating == exclude_rating) | ||
| 113 | continue; | ||
| 114 | if (gov->rating > max_rating) { | ||
| 115 | max_rating = gov->rating; | ||
| 116 | ret_gov = gov; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | return ret_gov; | ||
| 121 | } | ||
| 122 | |||
| 123 | /** | ||
| 124 | * cpuidle_unregister_governor - unregisters a governor | ||
| 125 | * @gov: the governor | ||
| 126 | */ | ||
| 127 | void cpuidle_unregister_governor(struct cpuidle_governor *gov) | ||
| 128 | { | ||
| 129 | if (!gov) | ||
| 130 | return; | ||
| 131 | |||
| 132 | mutex_lock(&cpuidle_lock); | ||
| 133 | if (gov == cpuidle_curr_governor) { | ||
| 134 | struct cpuidle_governor *new_gov; | ||
| 135 | new_gov = cpuidle_replace_governor(gov->rating); | ||
| 136 | cpuidle_switch_governor(new_gov); | ||
| 137 | } | ||
| 138 | list_del(&gov->governor_list); | ||
| 139 | mutex_unlock(&cpuidle_lock); | ||
| 140 | } | ||
| 141 | |||
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 8739cc05228c..e918b6d0caf7 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c | |||
| @@ -52,11 +52,12 @@ static ssize_t show_current_driver(struct device *dev, | |||
| 52 | char *buf) | 52 | char *buf) |
| 53 | { | 53 | { |
| 54 | ssize_t ret; | 54 | ssize_t ret; |
| 55 | struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); | 55 | struct cpuidle_driver *drv; |
| 56 | 56 | ||
| 57 | spin_lock(&cpuidle_driver_lock); | 57 | spin_lock(&cpuidle_driver_lock); |
| 58 | if (cpuidle_driver) | 58 | drv = cpuidle_get_driver(); |
| 59 | ret = sprintf(buf, "%s\n", cpuidle_driver->name); | 59 | if (drv) |
| 60 | ret = sprintf(buf, "%s\n", drv->name); | ||
| 60 | else | 61 | else |
| 61 | ret = sprintf(buf, "none\n"); | 62 | ret = sprintf(buf, "none\n"); |
| 62 | spin_unlock(&cpuidle_driver_lock); | 63 | spin_unlock(&cpuidle_driver_lock); |
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 33e599ebbe96..3f95a533c1a8 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
| @@ -390,7 +390,7 @@ static int cpu_hotplug_notify(struct notifier_block *n, | |||
| 390 | int hotcpu = (unsigned long)hcpu; | 390 | int hotcpu = (unsigned long)hcpu; |
| 391 | struct cpuidle_device *dev; | 391 | struct cpuidle_device *dev; |
| 392 | 392 | ||
| 393 | switch (action & 0xf) { | 393 | switch (action & ~CPU_TASKS_FROZEN) { |
| 394 | case CPU_ONLINE: | 394 | case CPU_ONLINE: |
| 395 | 395 | ||
| 396 | if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) | 396 | if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) |
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 781addc66f03..50fcbb0ac4e7 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h | |||
| @@ -114,7 +114,7 @@ struct cpuidle_driver { | |||
| 114 | int safe_state_index; | 114 | int safe_state_index; |
| 115 | 115 | ||
| 116 | /* the driver handles the cpus in cpumask */ | 116 | /* the driver handles the cpus in cpumask */ |
| 117 | struct cpumask *cpumask; | 117 | struct cpumask *cpumask; |
| 118 | }; | 118 | }; |
| 119 | 119 | ||
| 120 | #ifdef CONFIG_CPU_IDLE | 120 | #ifdef CONFIG_CPU_IDLE |
| @@ -195,16 +195,10 @@ struct cpuidle_governor { | |||
| 195 | }; | 195 | }; |
| 196 | 196 | ||
| 197 | #ifdef CONFIG_CPU_IDLE | 197 | #ifdef CONFIG_CPU_IDLE |
| 198 | |||
| 199 | extern int cpuidle_register_governor(struct cpuidle_governor *gov); | 198 | extern int cpuidle_register_governor(struct cpuidle_governor *gov); |
| 200 | extern void cpuidle_unregister_governor(struct cpuidle_governor *gov); | ||
| 201 | |||
| 202 | #else | 199 | #else |
| 203 | |||
| 204 | static inline int cpuidle_register_governor(struct cpuidle_governor *gov) | 200 | static inline int cpuidle_register_governor(struct cpuidle_governor *gov) |
| 205 | {return 0;} | 201 | {return 0;} |
| 206 | static inline void cpuidle_unregister_governor(struct cpuidle_governor *gov) { } | ||
| 207 | |||
| 208 | #endif | 202 | #endif |
| 209 | 203 | ||
| 210 | #ifdef CONFIG_ARCH_HAS_CPU_RELAX | 204 | #ifdef CONFIG_ARCH_HAS_CPU_RELAX |
