diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-08-19 19:42:32 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-08-20 19:23:53 -0400 |
commit | ad07277e82dedabacc52c82746633680a3187d25 (patch) | |
tree | fe2d921753be6d8cf4ed9e68b9ad8925212b17ea /drivers/acpi/sleep.c | |
parent | 1aaac07112f04068d7e2fc47bb435cfd4f9d5468 (diff) |
ACPI / PM: Hold acpi_scan_lock over system PM transitions
Bad things happen if ACPI hotplug events are handled during system
PM transitions, especially if devices are removed as a result.
To prevent those bad things from happening, acquire acpi_scan_lock
when a PM transition is started and release it when that transition
is complete or has been aborted.
This fixes resume lockup on my test-bed Acer Aspire S5 that happens
when Thunderbolt devices are disconnected from the machine while
suspended.
Also fixes the analogous problem for Mika Westerberg on an
Intel DZ77RE-75K board.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Toshi Kani <toshi.kani@hp.com>
Diffstat (limited to 'drivers/acpi/sleep.c')
-rw-r--r-- | drivers/acpi/sleep.c | 39 |
1 files changed, 24 insertions, 15 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 81b0f03d97db..1dec53decffa 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -420,10 +420,21 @@ static void acpi_pm_finish(void) | |||
420 | } | 420 | } |
421 | 421 | ||
422 | /** | 422 | /** |
423 | * acpi_pm_end - Finish up suspend sequence. | 423 | * acpi_pm_start - Start system PM transition. |
424 | */ | ||
425 | static void acpi_pm_start(u32 acpi_state) | ||
426 | { | ||
427 | acpi_target_sleep_state = acpi_state; | ||
428 | acpi_sleep_tts_switch(acpi_target_sleep_state); | ||
429 | acpi_scan_lock_acquire(); | ||
430 | } | ||
431 | |||
432 | /** | ||
433 | * acpi_pm_end - Finish up system PM transition. | ||
424 | */ | 434 | */ |
425 | static void acpi_pm_end(void) | 435 | static void acpi_pm_end(void) |
426 | { | 436 | { |
437 | acpi_scan_lock_release(); | ||
427 | /* | 438 | /* |
428 | * This is necessary in case acpi_pm_finish() is not called during a | 439 | * This is necessary in case acpi_pm_finish() is not called during a |
429 | * failing transition to a sleep state. | 440 | * failing transition to a sleep state. |
@@ -451,21 +462,19 @@ static u32 acpi_suspend_states[] = { | |||
451 | static int acpi_suspend_begin(suspend_state_t pm_state) | 462 | static int acpi_suspend_begin(suspend_state_t pm_state) |
452 | { | 463 | { |
453 | u32 acpi_state = acpi_suspend_states[pm_state]; | 464 | u32 acpi_state = acpi_suspend_states[pm_state]; |
454 | int error = 0; | 465 | int error; |
455 | 466 | ||
456 | error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc(); | 467 | error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc(); |
457 | if (error) | 468 | if (error) |
458 | return error; | 469 | return error; |
459 | 470 | ||
460 | if (sleep_states[acpi_state]) { | 471 | if (!sleep_states[acpi_state]) { |
461 | acpi_target_sleep_state = acpi_state; | 472 | pr_err("ACPI does not support sleep state S%u\n", acpi_state); |
462 | acpi_sleep_tts_switch(acpi_target_sleep_state); | 473 | return -ENOSYS; |
463 | } else { | ||
464 | printk(KERN_ERR "ACPI does not support this state: %d\n", | ||
465 | pm_state); | ||
466 | error = -ENOSYS; | ||
467 | } | 474 | } |
468 | return error; | 475 | |
476 | acpi_pm_start(acpi_state); | ||
477 | return 0; | ||
469 | } | 478 | } |
470 | 479 | ||
471 | /** | 480 | /** |
@@ -631,10 +640,8 @@ static int acpi_hibernation_begin(void) | |||
631 | int error; | 640 | int error; |
632 | 641 | ||
633 | error = nvs_nosave ? 0 : suspend_nvs_alloc(); | 642 | error = nvs_nosave ? 0 : suspend_nvs_alloc(); |
634 | if (!error) { | 643 | if (!error) |
635 | acpi_target_sleep_state = ACPI_STATE_S4; | 644 | acpi_pm_start(ACPI_STATE_S4); |
636 | acpi_sleep_tts_switch(acpi_target_sleep_state); | ||
637 | } | ||
638 | 645 | ||
639 | return error; | 646 | return error; |
640 | } | 647 | } |
@@ -713,8 +720,10 @@ static int acpi_hibernation_begin_old(void) | |||
713 | if (!error) { | 720 | if (!error) { |
714 | if (!nvs_nosave) | 721 | if (!nvs_nosave) |
715 | error = suspend_nvs_alloc(); | 722 | error = suspend_nvs_alloc(); |
716 | if (!error) | 723 | if (!error) { |
717 | acpi_target_sleep_state = ACPI_STATE_S4; | 724 | acpi_target_sleep_state = ACPI_STATE_S4; |
725 | acpi_scan_lock_acquire(); | ||
726 | } | ||
718 | } | 727 | } |
719 | return error; | 728 | return error; |
720 | } | 729 | } |