ACPI/CPUIDLE: prevent setting pm_idle to NULL

pm_idle_save resp. pm_idle_old can be NULL when the restore code in
acpi_processor_cst_has_changed() resp. cpuidle_uninstall_idle_handler()
is called. This can set pm_idle unconditinally to NULL, which causes the
kernel to panic when calling pm_idle in the x86 idle code. This was
covered by an extra check for !pm_idle in the x86 idle code, which was
removed during the x86 idle code refactoring.

Instead of restoring the pm_idle check in the x86 code prevent the
acpi/cpuidle code to set pm_idle to NULL.

Reported by: Dhaval Giani http://lkml.org/lkml/2008/7/2/309
Based on a debug patch from Ingo Molnar

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Thomas Gleixner and committed by
Linus Torvalds
b032bf70 9ffc1699

+12 -5
+11 -4
drivers/acpi/processor_idle.c
··· 1332 1332 if (!pr->flags.power_setup_done) 1333 1333 return -ENODEV; 1334 1334 1335 - /* Fall back to the default idle loop */ 1336 - pm_idle = pm_idle_save; 1337 - synchronize_sched(); /* Relies on interrupts forcing exit from idle. */ 1335 + /* 1336 + * Fall back to the default idle loop, when pm_idle_save had 1337 + * been initialized. 1338 + */ 1339 + if (pm_idle_save) { 1340 + pm_idle = pm_idle_save; 1341 + /* Relies on interrupts forcing exit from idle. */ 1342 + synchronize_sched(); 1343 + } 1338 1344 1339 1345 pr->flags.power = 0; 1340 1346 result = acpi_processor_get_power_info(pr); ··· 1902 1896 1903 1897 /* Unregister the idle handler when processor #0 is removed. */ 1904 1898 if (pr->id == 0) { 1905 - pm_idle = pm_idle_save; 1899 + if (pm_idle_save) 1900 + pm_idle = pm_idle_save; 1906 1901 1907 1902 /* 1908 1903 * We are about to unload the current idle thread pm callback
+1 -1
drivers/cpuidle/cpuidle.c
··· 94 94 */ 95 95 void cpuidle_uninstall_idle_handler(void) 96 96 { 97 - if (enabled_devices && (pm_idle != pm_idle_old)) { 97 + if (enabled_devices && pm_idle_old && (pm_idle != pm_idle_old)) { 98 98 pm_idle = pm_idle_old; 99 99 cpuidle_kick_cpus(); 100 100 }