Commit dcb84f335bee9c9a7781cfc5d74492dccaf066d2
Committed by
Len Brown
1 parent
e1094bfa26
Exists in
master
and in
7 other branches
cpuidle acpi driver: fix oops on AC<->DC
cpuidle and acpi driver interaction bug with the way cpuidle_register_driver() is called. Due to this bug, there will be oops on AC<->DC on some systems, where they support C-states in one DC and not in AC. The current code does ON BOOT: Look at CST and other C-state info to see whether more than C1 is supported. If it is, then acpi processor_idle does a cpuidle_register_driver() call, which internally enables the device. ON CST change notification (AC<->DC) and on suspend-resume: acpi driver temporarily disables device, updates the device with any new C-states, and reenables the device. The problem is is on boot, there are no C2, C3 states supported and we skip the register. Later on AC<->DC, we may get a CST notification and we try to reevaluate CST and enabled the device, without actually registering it. This causes breakage as we try to create /sys fs sub directory, without the parent directory which is created at register time. Thanks to Sanjeev for reporting the problem here. http://bugzilla.kernel.org/show_bug.cgi?id=10394 Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Showing 3 changed files with 43 additions and 11 deletions Side-by-side Diff
drivers/acpi/processor_idle.c
... | ... | @@ -1669,6 +1669,7 @@ |
1669 | 1669 | return -EINVAL; |
1670 | 1670 | } |
1671 | 1671 | |
1672 | + dev->cpu = pr->id; | |
1672 | 1673 | for (i = 0; i < CPUIDLE_STATE_MAX; i++) { |
1673 | 1674 | dev->states[i].name[0] = '\0'; |
1674 | 1675 | dev->states[i].desc[0] = '\0'; |
... | ... | @@ -1738,7 +1739,7 @@ |
1738 | 1739 | |
1739 | 1740 | int acpi_processor_cst_has_changed(struct acpi_processor *pr) |
1740 | 1741 | { |
1741 | - int ret; | |
1742 | + int ret = 0; | |
1742 | 1743 | |
1743 | 1744 | if (boot_option_idle_override) |
1744 | 1745 | return 0; |
... | ... | @@ -1756,8 +1757,10 @@ |
1756 | 1757 | cpuidle_pause_and_lock(); |
1757 | 1758 | cpuidle_disable_device(&pr->power.dev); |
1758 | 1759 | acpi_processor_get_power_info(pr); |
1759 | - acpi_processor_setup_cpuidle(pr); | |
1760 | - ret = cpuidle_enable_device(&pr->power.dev); | |
1760 | + if (pr->flags.power) { | |
1761 | + acpi_processor_setup_cpuidle(pr); | |
1762 | + ret = cpuidle_enable_device(&pr->power.dev); | |
1763 | + } | |
1761 | 1764 | cpuidle_resume_and_unlock(); |
1762 | 1765 | |
1763 | 1766 | return ret; |
... | ... | @@ -1813,7 +1816,6 @@ |
1813 | 1816 | if (pr->flags.power) { |
1814 | 1817 | #ifdef CONFIG_CPU_IDLE |
1815 | 1818 | acpi_processor_setup_cpuidle(pr); |
1816 | - pr->power.dev.cpu = pr->id; | |
1817 | 1819 | if (cpuidle_register_device(&pr->power.dev)) |
1818 | 1820 | return -EIO; |
1819 | 1821 | #endif |
... | ... | @@ -1850,8 +1852,7 @@ |
1850 | 1852 | return 0; |
1851 | 1853 | |
1852 | 1854 | #ifdef CONFIG_CPU_IDLE |
1853 | - if (pr->flags.power) | |
1854 | - cpuidle_unregister_device(&pr->power.dev); | |
1855 | + cpuidle_unregister_device(&pr->power.dev); | |
1855 | 1856 | #endif |
1856 | 1857 | pr->flags.power_setup_done = 0; |
1857 | 1858 |
drivers/cpuidle/cpuidle.c
... | ... | @@ -38,6 +38,8 @@ |
38 | 38 | static void cpuidle_kick_cpus(void) {} |
39 | 39 | #endif |
40 | 40 | |
41 | +static int __cpuidle_register_device(struct cpuidle_device *dev); | |
42 | + | |
41 | 43 | /** |
42 | 44 | * cpuidle_idle_call - the main idle loop |
43 | 45 | * |
... | ... | @@ -138,6 +140,12 @@ |
138 | 140 | if (!dev->state_count) |
139 | 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 | 149 | if ((ret = cpuidle_add_state_sysfs(dev))) |
142 | 150 | return ret; |
143 | 151 | |
144 | 152 | |
145 | 153 | |
... | ... | @@ -232,10 +240,13 @@ |
232 | 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 | 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 | 251 | int ret; |
241 | 252 | struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); |
242 | 253 | |
243 | 254 | |
... | ... | @@ -247,18 +258,34 @@ |
247 | 258 | |
248 | 259 | init_completion(&dev->kobj_unregister); |
249 | 260 | |
250 | - mutex_lock(&cpuidle_lock); | |
251 | - | |
252 | 261 | poll_idle_init(dev); |
253 | 262 | |
254 | 263 | per_cpu(cpuidle_devices, dev->cpu) = dev; |
255 | 264 | list_add(&dev->device_list, &cpuidle_detected_devices); |
256 | 265 | if ((ret = cpuidle_add_sysfs(sys_dev))) { |
257 | - mutex_unlock(&cpuidle_lock); | |
258 | 266 | module_put(cpuidle_curr_driver->owner); |
259 | 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 | 289 | cpuidle_enable_device(dev); |
263 | 290 | cpuidle_install_idle_handler(); |
264 | 291 | |
... | ... | @@ -277,6 +304,9 @@ |
277 | 304 | void cpuidle_unregister_device(struct cpuidle_device *dev) |
278 | 305 | { |
279 | 306 | struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); |
307 | + | |
308 | + if (dev->registered == 0) | |
309 | + return; | |
280 | 310 | |
281 | 311 | cpuidle_pause_and_lock(); |
282 | 312 |