diff options
| -rw-r--r-- | drivers/acpi/processor_idle.c | 13 | ||||
| -rw-r--r-- | drivers/cpuidle/cpuidle.c | 40 | ||||
| -rw-r--r-- | include/linux/cpuidle.h | 1 |
3 files changed, 43 insertions, 11 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 2dd2c1f3a01c..556ee1585192 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
| @@ -1669,6 +1669,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) | |||
| 1669 | return -EINVAL; | 1669 | return -EINVAL; |
| 1670 | } | 1670 | } |
| 1671 | 1671 | ||
| 1672 | dev->cpu = pr->id; | ||
| 1672 | for (i = 0; i < CPUIDLE_STATE_MAX; i++) { | 1673 | for (i = 0; i < CPUIDLE_STATE_MAX; i++) { |
| 1673 | dev->states[i].name[0] = '\0'; | 1674 | dev->states[i].name[0] = '\0'; |
| 1674 | dev->states[i].desc[0] = '\0'; | 1675 | dev->states[i].desc[0] = '\0'; |
| @@ -1738,7 +1739,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) | |||
| 1738 | 1739 | ||
| 1739 | int acpi_processor_cst_has_changed(struct acpi_processor *pr) | 1740 | int acpi_processor_cst_has_changed(struct acpi_processor *pr) |
| 1740 | { | 1741 | { |
| 1741 | int ret; | 1742 | int ret = 0; |
| 1742 | 1743 | ||
| 1743 | if (boot_option_idle_override) | 1744 | if (boot_option_idle_override) |
| 1744 | return 0; | 1745 | return 0; |
| @@ -1756,8 +1757,10 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) | |||
| 1756 | cpuidle_pause_and_lock(); | 1757 | cpuidle_pause_and_lock(); |
| 1757 | cpuidle_disable_device(&pr->power.dev); | 1758 | cpuidle_disable_device(&pr->power.dev); |
| 1758 | acpi_processor_get_power_info(pr); | 1759 | acpi_processor_get_power_info(pr); |
| 1759 | acpi_processor_setup_cpuidle(pr); | 1760 | if (pr->flags.power) { |
| 1760 | ret = cpuidle_enable_device(&pr->power.dev); | 1761 | acpi_processor_setup_cpuidle(pr); |
| 1762 | ret = cpuidle_enable_device(&pr->power.dev); | ||
| 1763 | } | ||
| 1761 | cpuidle_resume_and_unlock(); | 1764 | cpuidle_resume_and_unlock(); |
| 1762 | 1765 | ||
| 1763 | return ret; | 1766 | return ret; |
| @@ -1813,7 +1816,6 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, | |||
| 1813 | if (pr->flags.power) { | 1816 | if (pr->flags.power) { |
| 1814 | #ifdef CONFIG_CPU_IDLE | 1817 | #ifdef CONFIG_CPU_IDLE |
| 1815 | acpi_processor_setup_cpuidle(pr); | 1818 | acpi_processor_setup_cpuidle(pr); |
| 1816 | pr->power.dev.cpu = pr->id; | ||
| 1817 | if (cpuidle_register_device(&pr->power.dev)) | 1819 | if (cpuidle_register_device(&pr->power.dev)) |
| 1818 | return -EIO; | 1820 | return -EIO; |
| 1819 | #endif | 1821 | #endif |
| @@ -1850,8 +1852,7 @@ int acpi_processor_power_exit(struct acpi_processor *pr, | |||
| 1850 | return 0; | 1852 | return 0; |
| 1851 | 1853 | ||
| 1852 | #ifdef CONFIG_CPU_IDLE | 1854 | #ifdef CONFIG_CPU_IDLE |
| 1853 | if (pr->flags.power) | 1855 | cpuidle_unregister_device(&pr->power.dev); |
| 1854 | cpuidle_unregister_device(&pr->power.dev); | ||
| 1855 | #endif | 1856 | #endif |
| 1856 | pr->flags.power_setup_done = 0; | 1857 | pr->flags.power_setup_done = 0; |
| 1857 | 1858 | ||
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index fc555a90bb21..23554b676d6e 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
| @@ -38,6 +38,8 @@ static void cpuidle_kick_cpus(void) | |||
| 38 | static void cpuidle_kick_cpus(void) {} | 38 | static void cpuidle_kick_cpus(void) {} |
| 39 | #endif | 39 | #endif |
| 40 | 40 | ||
| 41 | static int __cpuidle_register_device(struct cpuidle_device *dev); | ||
| 42 | |||
| 41 | /** | 43 | /** |
| 42 | * cpuidle_idle_call - the main idle loop | 44 | * cpuidle_idle_call - the main idle loop |
| 43 | * | 45 | * |
| @@ -138,6 +140,12 @@ int cpuidle_enable_device(struct cpuidle_device *dev) | |||
| 138 | if (!dev->state_count) | 140 | if (!dev->state_count) |
| 139 | return -EINVAL; | 141 | return -EINVAL; |
| 140 | 142 | ||
| 143 | if (dev->registered == 0) { | ||
| 144 | ret = __cpuidle_register_device(dev); | ||
| 145 | if (ret) | ||
| 146 | return ret; | ||
| 147 | } | ||
| 148 | |||
| 141 | if ((ret = cpuidle_add_state_sysfs(dev))) | 149 | if ((ret = cpuidle_add_state_sysfs(dev))) |
| 142 | return ret; | 150 | return ret; |
| 143 | 151 | ||
| @@ -232,10 +240,13 @@ static void poll_idle_init(struct cpuidle_device *dev) {} | |||
| 232 | #endif /* CONFIG_ARCH_HAS_CPU_RELAX */ | 240 | #endif /* CONFIG_ARCH_HAS_CPU_RELAX */ |
| 233 | 241 | ||
| 234 | /** | 242 | /** |
| 235 | * cpuidle_register_device - registers a CPU's idle PM feature | 243 | * __cpuidle_register_device - internal register function called before register |
| 244 | * and enable routines | ||
| 236 | * @dev: the cpu | 245 | * @dev: the cpu |
| 246 | * | ||
| 247 | * cpuidle_lock mutex must be held before this is called | ||
| 237 | */ | 248 | */ |
| 238 | int cpuidle_register_device(struct cpuidle_device *dev) | 249 | static int __cpuidle_register_device(struct cpuidle_device *dev) |
| 239 | { | 250 | { |
| 240 | int ret; | 251 | int ret; |
| 241 | struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); | 252 | struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); |
| @@ -247,18 +258,34 @@ int cpuidle_register_device(struct cpuidle_device *dev) | |||
| 247 | 258 | ||
| 248 | init_completion(&dev->kobj_unregister); | 259 | init_completion(&dev->kobj_unregister); |
| 249 | 260 | ||
| 250 | mutex_lock(&cpuidle_lock); | ||
| 251 | |||
| 252 | poll_idle_init(dev); | 261 | poll_idle_init(dev); |
| 253 | 262 | ||
| 254 | per_cpu(cpuidle_devices, dev->cpu) = dev; | 263 | per_cpu(cpuidle_devices, dev->cpu) = dev; |
| 255 | list_add(&dev->device_list, &cpuidle_detected_devices); | 264 | list_add(&dev->device_list, &cpuidle_detected_devices); |
| 256 | if ((ret = cpuidle_add_sysfs(sys_dev))) { | 265 | if ((ret = cpuidle_add_sysfs(sys_dev))) { |
| 257 | mutex_unlock(&cpuidle_lock); | ||
| 258 | module_put(cpuidle_curr_driver->owner); | 266 | module_put(cpuidle_curr_driver->owner); |
| 259 | return ret; | 267 | return ret; |
| 260 | } | 268 | } |
| 261 | 269 | ||
| 270 | dev->registered = 1; | ||
| 271 | return 0; | ||
| 272 | } | ||
| 273 | |||
| 274 | /** | ||
| 275 | * cpuidle_register_device - registers a CPU's idle PM feature | ||
| 276 | * @dev: the cpu | ||
| 277 | */ | ||
| 278 | int cpuidle_register_device(struct cpuidle_device *dev) | ||
| 279 | { | ||
| 280 | int ret; | ||
| 281 | |||
| 282 | mutex_lock(&cpuidle_lock); | ||
| 283 | |||
| 284 | if ((ret = __cpuidle_register_device(dev))) { | ||
| 285 | mutex_unlock(&cpuidle_lock); | ||
| 286 | return ret; | ||
| 287 | } | ||
| 288 | |||
| 262 | cpuidle_enable_device(dev); | 289 | cpuidle_enable_device(dev); |
| 263 | cpuidle_install_idle_handler(); | 290 | cpuidle_install_idle_handler(); |
| 264 | 291 | ||
| @@ -278,6 +305,9 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) | |||
| 278 | { | 305 | { |
| 279 | struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); | 306 | struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); |
| 280 | 307 | ||
| 308 | if (dev->registered == 0) | ||
| 309 | return; | ||
| 310 | |||
| 281 | cpuidle_pause_and_lock(); | 311 | cpuidle_pause_and_lock(); |
| 282 | 312 | ||
| 283 | cpuidle_disable_device(dev); | 313 | cpuidle_disable_device(dev); |
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 51e6b1e520e6..dcf77fa826b5 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h | |||
| @@ -82,6 +82,7 @@ struct cpuidle_state_kobj { | |||
| 82 | }; | 82 | }; |
| 83 | 83 | ||
| 84 | struct cpuidle_device { | 84 | struct cpuidle_device { |
| 85 | unsigned int registered:1; | ||
| 85 | unsigned int enabled:1; | 86 | unsigned int enabled:1; |
| 86 | unsigned int cpu; | 87 | unsigned int cpu; |
| 87 | 88 | ||
