summaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-05-15 23:29:57 +0200
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-05-16 12:18:27 +0200
commit1f0b63866fc1be700260547be8edf8e6f0af37f2 (patch)
tree19834a42634cdc86a0addca25d1f71cbf408b273 /kernel/power
parentACPI / PM: Export acpi_target_system_state() to modules (diff)
downloadlinux-1f0b63866fc1be700260547be8edf8e6f0af37f2.tar.xz
linux-1f0b63866fc1be700260547be8edf8e6f0af37f2.zip
ACPI / PM: Hold ACPI scan lock over the "freeze" sleep state
The "freeze" sleep state suffers from the same issue that was addressed by commit ad07277e82de (ACPI / PM: Hold acpi_scan_lock over system PM transitions) for ACPI sleep states, that is, things break if ->remove() is called for devices whose system resume callbacks haven't been executed yet. It also can be addressed in the same way, by holding the ACPI scan lock over the "freeze" sleep state and PM transitions to and from that state, but ->begin() and ->end() platform operations for the "freeze" sleep state are needed for this purpose. This change has been tested on Acer Aspire S5 with Thunderbolt. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/suspend.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 8233cd4047d7..73a905f83972 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -38,6 +38,7 @@ const char *const pm_states[PM_SUSPEND_MAX] = {
};
static const struct platform_suspend_ops *suspend_ops;
+static const struct platform_freeze_ops *freeze_ops;
static bool need_suspend_ops(suspend_state_t state)
{
@@ -47,6 +48,13 @@ static bool need_suspend_ops(suspend_state_t state)
static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head);
static bool suspend_freeze_wake;
+void freeze_set_ops(const struct platform_freeze_ops *ops)
+{
+ lock_system_sleep();
+ freeze_ops = ops;
+ unlock_system_sleep();
+}
+
static void freeze_begin(void)
{
suspend_freeze_wake = false;
@@ -269,6 +277,10 @@ int suspend_devices_and_enter(suspend_state_t state)
error = suspend_ops->begin(state);
if (error)
goto Close;
+ } else if (state == PM_SUSPEND_FREEZE && freeze_ops->begin) {
+ error = freeze_ops->begin();
+ if (error)
+ goto Close;
}
suspend_console();
suspend_test_start();
@@ -294,6 +306,9 @@ int suspend_devices_and_enter(suspend_state_t state)
Close:
if (need_suspend_ops(state) && suspend_ops->end)
suspend_ops->end();
+ else if (state == PM_SUSPEND_FREEZE && freeze_ops->end)
+ freeze_ops->end();
+
trace_machine_suspend(PWR_EVENT_EXIT);
return error;