diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2008-06-12 17:24:06 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2008-06-12 17:25:09 -0400 |
commit | d8f3de0d2412bb91639cfefc5b3c79dbf3812212 (patch) | |
tree | 05d0530d06e898b7eeac5c781ee9f00972a7f67a /kernel/power | |
parent | 53eb2fbeb9e68e1a9a23945de8450999c46270ce (diff) |
Suspend-related patches for 2.6.27
ACPI PM: Add possibility to change suspend sequence
There are some systems out there that don't work correctly with
our current suspend/hibernation code ordering. Provide a workaround
for these systems allowing them to pass 'acpi_sleep=old_ordering' in
the kernel command line so that it will use the pre-ACPI 2.0 ("old")
suspend code ordering.
Unfortunately, this requires us to add a platform hook to the
resuming of devices for recovering the platform in case one of the
device drivers' .suspend() routines returns error code. Namely,
ACPI 1.0 specifies that _PTS should be called before suspending
devices, but _WAK still should be called before resuming them in
order to undo the changes made by _PTS. However, if there is an
error during suspending devices, they are automatically resumed
without returning control to the PM core, so the _WAK has to be
called from within device_resume() in that cases.
The patch also reorders and refactors the ACPI suspend/hibernation
code to avoid duplication as far as reasonably possible.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/disk.c | 28 | ||||
-rw-r--r-- | kernel/power/main.c | 10 |
2 files changed, 29 insertions, 9 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index d416be0efa8a..f011e0870b52 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -180,6 +180,17 @@ static void platform_restore_cleanup(int platform_mode) | |||
180 | } | 180 | } |
181 | 181 | ||
182 | /** | 182 | /** |
183 | * platform_recover - recover the platform from a failure to suspend | ||
184 | * devices. | ||
185 | */ | ||
186 | |||
187 | static void platform_recover(int platform_mode) | ||
188 | { | ||
189 | if (platform_mode && hibernation_ops && hibernation_ops->recover) | ||
190 | hibernation_ops->recover(); | ||
191 | } | ||
192 | |||
193 | /** | ||
183 | * create_image - freeze devices that need to be frozen with interrupts | 194 | * create_image - freeze devices that need to be frozen with interrupts |
184 | * off, create the hibernation image and thaw those devices. Control | 195 | * off, create the hibernation image and thaw those devices. Control |
185 | * reappears in this routine after a restore. | 196 | * reappears in this routine after a restore. |
@@ -258,10 +269,10 @@ int hibernation_snapshot(int platform_mode) | |||
258 | suspend_console(); | 269 | suspend_console(); |
259 | error = device_suspend(PMSG_FREEZE); | 270 | error = device_suspend(PMSG_FREEZE); |
260 | if (error) | 271 | if (error) |
261 | goto Resume_console; | 272 | goto Recover_platform; |
262 | 273 | ||
263 | if (hibernation_test(TEST_DEVICES)) | 274 | if (hibernation_test(TEST_DEVICES)) |
264 | goto Resume_devices; | 275 | goto Recover_platform; |
265 | 276 | ||
266 | error = platform_pre_snapshot(platform_mode); | 277 | error = platform_pre_snapshot(platform_mode); |
267 | if (error || hibernation_test(TEST_PLATFORM)) | 278 | if (error || hibernation_test(TEST_PLATFORM)) |
@@ -285,11 +296,14 @@ int hibernation_snapshot(int platform_mode) | |||
285 | Resume_devices: | 296 | Resume_devices: |
286 | device_resume(in_suspend ? | 297 | device_resume(in_suspend ? |
287 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 298 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
288 | Resume_console: | ||
289 | resume_console(); | 299 | resume_console(); |
290 | Close: | 300 | Close: |
291 | platform_end(platform_mode); | 301 | platform_end(platform_mode); |
292 | return error; | 302 | return error; |
303 | |||
304 | Recover_platform: | ||
305 | platform_recover(platform_mode); | ||
306 | goto Resume_devices; | ||
293 | } | 307 | } |
294 | 308 | ||
295 | /** | 309 | /** |
@@ -398,8 +412,11 @@ int hibernation_platform_enter(void) | |||
398 | 412 | ||
399 | suspend_console(); | 413 | suspend_console(); |
400 | error = device_suspend(PMSG_HIBERNATE); | 414 | error = device_suspend(PMSG_HIBERNATE); |
401 | if (error) | 415 | if (error) { |
402 | goto Resume_console; | 416 | if (hibernation_ops->recover) |
417 | hibernation_ops->recover(); | ||
418 | goto Resume_devices; | ||
419 | } | ||
403 | 420 | ||
404 | error = hibernation_ops->prepare(); | 421 | error = hibernation_ops->prepare(); |
405 | if (error) | 422 | if (error) |
@@ -428,7 +445,6 @@ int hibernation_platform_enter(void) | |||
428 | hibernation_ops->finish(); | 445 | hibernation_ops->finish(); |
429 | Resume_devices: | 446 | Resume_devices: |
430 | device_resume(PMSG_RESTORE); | 447 | device_resume(PMSG_RESTORE); |
431 | Resume_console: | ||
432 | resume_console(); | 448 | resume_console(); |
433 | Close: | 449 | Close: |
434 | hibernation_ops->end(); | 450 | hibernation_ops->end(); |
diff --git a/kernel/power/main.c b/kernel/power/main.c index d023b6b584e5..3398f4651aa1 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -269,11 +269,11 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
269 | error = device_suspend(PMSG_SUSPEND); | 269 | error = device_suspend(PMSG_SUSPEND); |
270 | if (error) { | 270 | if (error) { |
271 | printk(KERN_ERR "PM: Some devices failed to suspend\n"); | 271 | printk(KERN_ERR "PM: Some devices failed to suspend\n"); |
272 | goto Resume_console; | 272 | goto Recover_platform; |
273 | } | 273 | } |
274 | 274 | ||
275 | if (suspend_test(TEST_DEVICES)) | 275 | if (suspend_test(TEST_DEVICES)) |
276 | goto Resume_devices; | 276 | goto Recover_platform; |
277 | 277 | ||
278 | if (suspend_ops->prepare) { | 278 | if (suspend_ops->prepare) { |
279 | error = suspend_ops->prepare(); | 279 | error = suspend_ops->prepare(); |
@@ -294,12 +294,16 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
294 | suspend_ops->finish(); | 294 | suspend_ops->finish(); |
295 | Resume_devices: | 295 | Resume_devices: |
296 | device_resume(PMSG_RESUME); | 296 | device_resume(PMSG_RESUME); |
297 | Resume_console: | ||
298 | resume_console(); | 297 | resume_console(); |
299 | Close: | 298 | Close: |
300 | if (suspend_ops->end) | 299 | if (suspend_ops->end) |
301 | suspend_ops->end(); | 300 | suspend_ops->end(); |
302 | return error; | 301 | return error; |
302 | |||
303 | Recover_platform: | ||
304 | if (suspend_ops->recover) | ||
305 | suspend_ops->recover(); | ||
306 | goto Resume_devices; | ||
303 | } | 307 | } |
304 | 308 | ||
305 | /** | 309 | /** |