aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/sleep.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-08-19 19:42:32 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-08-20 19:23:53 -0400
commitad07277e82dedabacc52c82746633680a3187d25 (patch)
treefe2d921753be6d8cf4ed9e68b9ad8925212b17ea /drivers/acpi/sleep.c
parent1aaac07112f04068d7e2fc47bb435cfd4f9d5468 (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.c39
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 */
425static 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 */
425static void acpi_pm_end(void) 435static 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[] = {
451static int acpi_suspend_begin(suspend_state_t pm_state) 462static 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}