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>
        if (!pr->flags.power_setup_done)
                return -ENODEV;
 
-       /* Fall back to the default idle loop */
-       pm_idle = pm_idle_save;
-       synchronize_sched();    /* Relies on interrupts forcing exit from idle. */
+       /*
+        * Fall back to the default idle loop, when pm_idle_save had
+        * been initialized.
+        */
+       if (pm_idle_save) {
+               pm_idle = pm_idle_save;
+               /* Relies on interrupts forcing exit from idle. */
+               synchronize_sched();
+       }
 
        pr->flags.power = 0;
        result = acpi_processor_get_power_info(pr);
 
        /* Unregister the idle handler when processor #0 is removed. */
        if (pr->id == 0) {
-               pm_idle = pm_idle_save;
+               if (pm_idle_save)
+                       pm_idle = pm_idle_save;
 
                /*
                 * We are about to unload the current idle thread pm callback
 
  */
 void cpuidle_uninstall_idle_handler(void)
 {
-       if (enabled_devices && (pm_idle != pm_idle_old)) {
+       if (enabled_devices && pm_idle_old && (pm_idle != pm_idle_old)) {
                pm_idle = pm_idle_old;
                cpuidle_kick_cpus();
        }