aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2008-01-07 18:09:58 -0500
committerLen Brown <len.brown@intel.com>2008-02-01 18:30:58 -0500
commit7258ec5d11ead6db25575734f10f4586c0157463 (patch)
treeeaba68eb4ec9ac40f058166420b4b056d8b7c33a /drivers/acpi
parentcaea99ef339af8e07cda8d03fa415e4b8820f400 (diff)
ACPI hibernation: Call _PTS before suspending devices
The ACPI 1.0 specification wants us to put devices into low power states after executing the _PTS global control method, while ACPI 2.0 and later want us to do that in the reverse order. The current hibernation code follows ACPI 2.0 in that respect which may cause some ACPI 1.0x systems to hang during hibernation (ref. http://bugzilla.kernel.org/show_bug.cgi?id=9528). Make the hibernation code execute _PTS before putting devices into low power states (ie. in accordance with ACPI 1.0x) with the possibility to override that using the 'acpi_new_pts_ordering' kernel command line option. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/sleep/main.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 31e8e58e1cec..10db8991bd15 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -283,22 +283,34 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
283#ifdef CONFIG_HIBERNATION 283#ifdef CONFIG_HIBERNATION
284static int acpi_hibernation_begin(void) 284static int acpi_hibernation_begin(void)
285{ 285{
286 int error;
287
286 acpi_target_sleep_state = ACPI_STATE_S4; 288 acpi_target_sleep_state = ACPI_STATE_S4;
287 return 0; 289 if (new_pts_ordering)
290 return 0;
291
292 error = acpi_sleep_prepare(ACPI_STATE_S4);
293 if (error)
294 acpi_target_sleep_state = ACPI_STATE_S0;
295 else
296 acpi_sleep_finish_wake_up = true;
297
298 return error;
288} 299}
289 300
290static int acpi_hibernation_prepare(void) 301static int acpi_hibernation_prepare(void)
291{ 302{
292 int error; 303 if (new_pts_ordering) {
293 304 int error = acpi_sleep_prepare(ACPI_STATE_S4);
294 error = acpi_sleep_prepare(ACPI_STATE_S4);
295 if (error)
296 return error;
297 305
298 if (!ACPI_SUCCESS(acpi_hw_disable_all_gpes())) 306 if (error) {
299 error = -EFAULT; 307 acpi_target_sleep_state = ACPI_STATE_S0;
308 return error;
309 }
310 acpi_sleep_finish_wake_up = true;
311 }
300 312
301 return error; 313 return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
302} 314}
303 315
304static int acpi_hibernation_enter(void) 316static int acpi_hibernation_enter(void)
@@ -339,15 +351,17 @@ static void acpi_hibernation_finish(void)
339 acpi_set_firmware_waking_vector((acpi_physical_address) 0); 351 acpi_set_firmware_waking_vector((acpi_physical_address) 0);
340 352
341 acpi_target_sleep_state = ACPI_STATE_S0; 353 acpi_target_sleep_state = ACPI_STATE_S0;
354 acpi_sleep_finish_wake_up = false;
342} 355}
343 356
344static void acpi_hibernation_end(void) 357static void acpi_hibernation_end(void)
345{ 358{
346 /* 359 /*
347 * This is necessary in case acpi_hibernation_finish() is not called 360 * This is necessary in case acpi_hibernation_finish() is not called
348 * during a failing transition to the sleep state. 361 * directly during a failing transition to the sleep state.
349 */ 362 */
350 acpi_target_sleep_state = ACPI_STATE_S0; 363 if (acpi_sleep_finish_wake_up)
364 acpi_hibernation_finish();
351} 365}
352 366
353static int acpi_hibernation_pre_restore(void) 367static int acpi_hibernation_pre_restore(void)