Commit ad07277e authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

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: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: default avatarToshi Kani <toshi.kani@hp.com>
parent 1aaac071
...@@ -420,10 +420,21 @@ static void acpi_pm_finish(void) ...@@ -420,10 +420,21 @@ static void acpi_pm_finish(void)
} }
/** /**
* acpi_pm_end - Finish up suspend sequence. * acpi_pm_start - Start system PM transition.
*/
static void acpi_pm_start(u32 acpi_state)
{
acpi_target_sleep_state = acpi_state;
acpi_sleep_tts_switch(acpi_target_sleep_state);
acpi_scan_lock_acquire();
}
/**
* acpi_pm_end - Finish up system PM transition.
*/ */
static void acpi_pm_end(void) static void acpi_pm_end(void)
{ {
acpi_scan_lock_release();
/* /*
* This is necessary in case acpi_pm_finish() is not called during a * This is necessary in case acpi_pm_finish() is not called during a
* failing transition to a sleep state. * failing transition to a sleep state.
...@@ -451,21 +462,19 @@ static u32 acpi_suspend_states[] = { ...@@ -451,21 +462,19 @@ static u32 acpi_suspend_states[] = {
static int acpi_suspend_begin(suspend_state_t pm_state) static int acpi_suspend_begin(suspend_state_t pm_state)
{ {
u32 acpi_state = acpi_suspend_states[pm_state]; u32 acpi_state = acpi_suspend_states[pm_state];
int error = 0; int error;
error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc(); error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc();
if (error) if (error)
return error; return error;
if (sleep_states[acpi_state]) { if (!sleep_states[acpi_state]) {
acpi_target_sleep_state = acpi_state; pr_err("ACPI does not support sleep state S%u\n", acpi_state);
acpi_sleep_tts_switch(acpi_target_sleep_state); return -ENOSYS;
} else {
printk(KERN_ERR "ACPI does not support this state: %d\n",
pm_state);
error = -ENOSYS;
} }
return error;
acpi_pm_start(acpi_state);
return 0;
} }
/** /**
...@@ -631,10 +640,8 @@ static int acpi_hibernation_begin(void) ...@@ -631,10 +640,8 @@ static int acpi_hibernation_begin(void)
int error; int error;
error = nvs_nosave ? 0 : suspend_nvs_alloc(); error = nvs_nosave ? 0 : suspend_nvs_alloc();
if (!error) { if (!error)
acpi_target_sleep_state = ACPI_STATE_S4; acpi_pm_start(ACPI_STATE_S4);
acpi_sleep_tts_switch(acpi_target_sleep_state);
}
return error; return error;
} }
...@@ -713,8 +720,10 @@ static int acpi_hibernation_begin_old(void) ...@@ -713,8 +720,10 @@ static int acpi_hibernation_begin_old(void)
if (!error) { if (!error) {
if (!nvs_nosave) if (!nvs_nosave)
error = suspend_nvs_alloc(); error = suspend_nvs_alloc();
if (!error) if (!error) {
acpi_target_sleep_state = ACPI_STATE_S4; acpi_target_sleep_state = ACPI_STATE_S4;
acpi_scan_lock_acquire();
}
} }
return error; return error;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment