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>
This commit is contained in:
Thomas Gleixner 2008-07-27 23:47:12 +02:00 committed by Linus Torvalds
parent 9ffc1699e3
commit b032bf70df
2 changed files with 12 additions and 5 deletions

View File

@ -1332,9 +1332,15 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
if (!pr->flags.power_setup_done) if (!pr->flags.power_setup_done)
return -ENODEV; return -ENODEV;
/* Fall back to the default idle loop */ /*
* Fall back to the default idle loop, when pm_idle_save had
* been initialized.
*/
if (pm_idle_save) {
pm_idle = pm_idle_save; pm_idle = pm_idle_save;
synchronize_sched(); /* Relies on interrupts forcing exit from idle. */ /* Relies on interrupts forcing exit from idle. */
synchronize_sched();
}
pr->flags.power = 0; pr->flags.power = 0;
result = acpi_processor_get_power_info(pr); result = acpi_processor_get_power_info(pr);
@ -1896,6 +1902,7 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
/* Unregister the idle handler when processor #0 is removed. */ /* Unregister the idle handler when processor #0 is removed. */
if (pr->id == 0) { if (pr->id == 0) {
if (pm_idle_save)
pm_idle = pm_idle_save; pm_idle = pm_idle_save;
/* /*

View File

@ -94,7 +94,7 @@ void cpuidle_install_idle_handler(void)
*/ */
void cpuidle_uninstall_idle_handler(void) 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; pm_idle = pm_idle_old;
cpuidle_kick_cpus(); cpuidle_kick_cpus();
} }