diff options
author | Matthew Garrett <mjg@redhat.com> | 2010-05-28 16:32:15 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2010-06-10 11:03:15 -0400 |
commit | 2a6b69765ad794389f2fc3e14a0afa1a995221c2 (patch) | |
tree | 63c22656f682ba94cdeb882ee370966af57f41c9 /drivers/acpi | |
parent | dd4c4f17d722ffeb2515bf781400675a30fcead7 (diff) |
ACPI: Store NVS state even when entering suspend to RAM
https://bugzilla.kernel.org/show_bug.cgi?id=13931 describes a bug where
a system fails to successfully resume after the second suspend. Maxim
Levitsky discovered that this could be rectified by forcibly saving
and restoring the ACPI non-volatile state. The spec indicates that this
is only required for S4, but testing the behaviour of Windows by adding
an ACPI NVS region to qemu's e820 map and registering a custom memory
read/write handler reveals that it's saved and restored even over suspend
to RAM. We should mimic that behaviour to avoid other broken platforms.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/sleep.c | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index bcaa6efa8136..403daf0fc8a0 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -112,6 +112,8 @@ static int __acpi_pm_prepare(void) | |||
112 | { | 112 | { |
113 | int error = acpi_sleep_prepare(acpi_target_sleep_state); | 113 | int error = acpi_sleep_prepare(acpi_target_sleep_state); |
114 | 114 | ||
115 | suspend_nvs_save(); | ||
116 | |||
115 | if (error) | 117 | if (error) |
116 | acpi_target_sleep_state = ACPI_STATE_S0; | 118 | acpi_target_sleep_state = ACPI_STATE_S0; |
117 | return error; | 119 | return error; |
@@ -140,6 +142,8 @@ static void acpi_pm_finish(void) | |||
140 | { | 142 | { |
141 | u32 acpi_state = acpi_target_sleep_state; | 143 | u32 acpi_state = acpi_target_sleep_state; |
142 | 144 | ||
145 | suspend_nvs_free(); | ||
146 | |||
143 | if (acpi_state == ACPI_STATE_S0) | 147 | if (acpi_state == ACPI_STATE_S0) |
144 | return; | 148 | return; |
145 | 149 | ||
@@ -189,6 +193,11 @@ static int acpi_suspend_begin(suspend_state_t pm_state) | |||
189 | u32 acpi_state = acpi_suspend_states[pm_state]; | 193 | u32 acpi_state = acpi_suspend_states[pm_state]; |
190 | int error = 0; | 194 | int error = 0; |
191 | 195 | ||
196 | error = suspend_nvs_alloc(); | ||
197 | |||
198 | if (error) | ||
199 | return error; | ||
200 | |||
192 | if (sleep_states[acpi_state]) { | 201 | if (sleep_states[acpi_state]) { |
193 | acpi_target_sleep_state = acpi_state; | 202 | acpi_target_sleep_state = acpi_state; |
194 | acpi_sleep_tts_switch(acpi_target_sleep_state); | 203 | acpi_sleep_tts_switch(acpi_target_sleep_state); |
@@ -264,6 +273,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state) | |||
264 | if (acpi_state == ACPI_STATE_S3) | 273 | if (acpi_state == ACPI_STATE_S3) |
265 | acpi_restore_state_mem(); | 274 | acpi_restore_state_mem(); |
266 | 275 | ||
276 | suspend_nvs_restore(); | ||
277 | |||
267 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; | 278 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; |
268 | } | 279 | } |
269 | 280 | ||
@@ -430,12 +441,6 @@ static int acpi_hibernation_enter(void) | |||
430 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; | 441 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; |
431 | } | 442 | } |
432 | 443 | ||
433 | static void acpi_hibernation_finish(void) | ||
434 | { | ||
435 | suspend_nvs_free(); | ||
436 | acpi_pm_finish(); | ||
437 | } | ||
438 | |||
439 | static void acpi_hibernation_leave(void) | 444 | static void acpi_hibernation_leave(void) |
440 | { | 445 | { |
441 | /* | 446 | /* |
@@ -473,7 +478,7 @@ static struct platform_hibernation_ops acpi_hibernation_ops = { | |||
473 | .begin = acpi_hibernation_begin, | 478 | .begin = acpi_hibernation_begin, |
474 | .end = acpi_pm_end, | 479 | .end = acpi_pm_end, |
475 | .pre_snapshot = acpi_hibernation_pre_snapshot, | 480 | .pre_snapshot = acpi_hibernation_pre_snapshot, |
476 | .finish = acpi_hibernation_finish, | 481 | .finish = acpi_pm_finish, |
477 | .prepare = acpi_pm_prepare, | 482 | .prepare = acpi_pm_prepare, |
478 | .enter = acpi_hibernation_enter, | 483 | .enter = acpi_hibernation_enter, |
479 | .leave = acpi_hibernation_leave, | 484 | .leave = acpi_hibernation_leave, |
@@ -526,7 +531,7 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = { | |||
526 | .begin = acpi_hibernation_begin_old, | 531 | .begin = acpi_hibernation_begin_old, |
527 | .end = acpi_pm_end, | 532 | .end = acpi_pm_end, |
528 | .pre_snapshot = acpi_hibernation_pre_snapshot_old, | 533 | .pre_snapshot = acpi_hibernation_pre_snapshot_old, |
529 | .finish = acpi_hibernation_finish, | 534 | .finish = acpi_pm_finish, |
530 | .prepare = acpi_pm_disable_gpes, | 535 | .prepare = acpi_pm_disable_gpes, |
531 | .enter = acpi_hibernation_enter, | 536 | .enter = acpi_hibernation_enter, |
532 | .leave = acpi_hibernation_leave, | 537 | .leave = acpi_hibernation_leave, |