summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2007-09-23 02:29:05 +0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-11-02 18:44:08 +0300
commitf310d0f08fdf2c9ed846ddcb958c50507c7833b9 (patch)
treeadac593ffe806c2e5630e341fbc88ff6535f8440
parent86b74fc0fc26a58b6a93a4e57eae7989dcfbf305 (diff)
downloadlinux-f310d0f08fdf2c9ed846ddcb958c50507c7833b9.tar.xz
ACPI: disable lower idle C-states across suspend/resume
changeset b04e7bdb984e3b7f62fb7f44146a529f88cc7639 from mainline. device_suspend() calls ACPI suspend functions, which seems to have undesired side effects on lower idle C-states. It took me some time to realize that especially the VAIO BIOSes (both Andrews jinxed UP and my elfstruck SMP one) show this effect. I'm quite sure that other bug reports against suspend/resume about turning the system into a brick have the same root cause. After fishing in the dark for quite some time, I realized that removing the ACPI processor module before suspend (this removes the lower C-state functionality) made the problem disappear. Interestingly enough the propability of having a bricked box is influenced by various factors (interrupts, size of the ram image, ...). Even adding a bunch of printks in the wrong places made the problem go away. The previous periodic tick implementation simply pampered over the problem, which explains why the dyntick / clockevents changes made this more prominent. We avoid complex functionality during the boot process and we have to do the same during suspend/resume. It is a similar scenario and equaly fragile. Add suspend / resume functions to the ACPI processor code and disable the lower idle C-states across suspend/resume. Fall back to the default idle implementation (halt) instead. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Andrew Morton <akpm@linux-foundation.org> Cc: Len Brown <lenb@kernel.org> Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Cc: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/acpi/processor_core.c2
-rw-r--r--drivers/acpi/processor_idle.c19
-rw-r--r--include/acpi/processor.h2
3 files changed, 22 insertions, 1 deletions
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index f7de02a6f497..e529f4c2bbe2 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -93,6 +93,8 @@ static struct acpi_driver acpi_processor_driver = {
.add = acpi_processor_add,
.remove = acpi_processor_remove,
.start = acpi_processor_start,
+ .suspend = acpi_processor_suspend,
+ .resume = acpi_processor_resume,
},
};
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 80ffc7829916..13915e8d81ca 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -324,6 +324,23 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
#endif
+/*
+ * Suspend / resume control
+ */
+static int acpi_idle_suspend;
+
+int acpi_processor_suspend(struct acpi_device * device, pm_message_t state)
+{
+ acpi_idle_suspend = 1;
+ return 0;
+}
+
+int acpi_processor_resume(struct acpi_device * device)
+{
+ acpi_idle_suspend = 0;
+ return 0;
+}
+
static void acpi_processor_idle(void)
{
struct acpi_processor *pr = NULL;
@@ -354,7 +371,7 @@ static void acpi_processor_idle(void)
}
cx = pr->power.state;
- if (!cx) {
+ if (!cx || acpi_idle_suspend) {
if (pm_idle_save)
pm_idle_save();
else
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index b4b0ffdab098..0276fc6ec5f8 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -279,6 +279,8 @@ int acpi_processor_power_init(struct acpi_processor *pr,
int acpi_processor_cst_has_changed(struct acpi_processor *pr);
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device);
+int acpi_processor_suspend(struct acpi_device * device, pm_message_t state);
+int acpi_processor_resume(struct acpi_device * device);
/* in processor_thermal.c */
int acpi_processor_get_limit_info(struct acpi_processor *pr);