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>

authored by Rafael J. Wysocki and committed by Len Brown 7258ec5d caea99ef

+25 -11
+25 -11
drivers/acpi/sleep/main.c
··· 283 #ifdef CONFIG_HIBERNATION 284 static int acpi_hibernation_begin(void) 285 { 286 acpi_target_sleep_state = ACPI_STATE_S4; 287 - return 0; 288 } 289 290 static int acpi_hibernation_prepare(void) 291 { 292 - int error; 293 294 - error = acpi_sleep_prepare(ACPI_STATE_S4); 295 - if (error) 296 - return error; 297 298 - if (!ACPI_SUCCESS(acpi_hw_disable_all_gpes())) 299 - error = -EFAULT; 300 - 301 - return error; 302 } 303 304 static int acpi_hibernation_enter(void) ··· 351 acpi_set_firmware_waking_vector((acpi_physical_address) 0); 352 353 acpi_target_sleep_state = ACPI_STATE_S0; 354 } 355 356 static void acpi_hibernation_end(void) 357 { 358 /* 359 * This is necessary in case acpi_hibernation_finish() is not called 360 - * during a failing transition to the sleep state. 361 */ 362 - acpi_target_sleep_state = ACPI_STATE_S0; 363 } 364 365 static int acpi_hibernation_pre_restore(void)
··· 283 #ifdef CONFIG_HIBERNATION 284 static int acpi_hibernation_begin(void) 285 { 286 + int error; 287 + 288 acpi_target_sleep_state = ACPI_STATE_S4; 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; 299 } 300 301 static int acpi_hibernation_prepare(void) 302 { 303 + if (new_pts_ordering) { 304 + int error = acpi_sleep_prepare(ACPI_STATE_S4); 305 306 + if (error) { 307 + acpi_target_sleep_state = ACPI_STATE_S0; 308 + return error; 309 + } 310 + acpi_sleep_finish_wake_up = true; 311 + } 312 313 + return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT; 314 } 315 316 static int acpi_hibernation_enter(void) ··· 339 acpi_set_firmware_waking_vector((acpi_physical_address) 0); 340 341 acpi_target_sleep_state = ACPI_STATE_S0; 342 + acpi_sleep_finish_wake_up = false; 343 } 344 345 static void acpi_hibernation_end(void) 346 { 347 /* 348 * This is necessary in case acpi_hibernation_finish() is not called 349 + * directly during a failing transition to the sleep state. 350 */ 351 + if (acpi_sleep_finish_wake_up) 352 + acpi_hibernation_finish(); 353 } 354 355 static int acpi_hibernation_pre_restore(void)