aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/hibernate.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-01-29 14:38:29 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2012-01-29 14:38:29 -0500
commitcf579dfb82550e34de7ccf3ef090d8b834ccd3a9 (patch)
tree764ed72670c18c86d3eb9650025c56d661a31315 /kernel/power/hibernate.c
parent181e9bdef37bfcaa41f3ab6c948a2a0d60a268b5 (diff)
PM / Sleep: Introduce "late suspend" and "early resume" of devices
The current device suspend/resume phases during system-wide power transitions appear to be insufficient for some platforms that want to use the same callback routines for saving device states and related operations during runtime suspend/resume as well as during system suspend/resume. In principle, they could point their .suspend_noirq() and .resume_noirq() to the same callback routines as their .runtime_suspend() and .runtime_resume(), respectively, but at least some of them require device interrupts to be enabled while the code in those routines is running. It also makes sense to have device suspend-resume callbacks that will be executed with runtime PM disabled and with device interrupts enabled in case someone needs to run some special code in that context during system-wide power transitions. Apart from this, .suspend_noirq() and .resume_noirq() were introduced as a workaround for drivers using shared interrupts and failing to prevent their interrupt handlers from accessing suspended hardware. It appears to be better not to use them for other porposes, or we may have to deal with some serious confusion (which seems to be happening already). For the above reasons, introduce new device suspend/resume phases, "late suspend" and "early resume" (and analogously for hibernation) whose callback will be executed with runtime PM disabled and with device interrupts enabled and whose callback pointers generally may point to runtime suspend/resume routines. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Reviewed-by: Kevin Hilman <khilman@ti.com>
Diffstat (limited to 'kernel/power/hibernate.c')
-rw-r--r--kernel/power/hibernate.c24
1 files changed, 12 insertions, 12 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 6d6d28870335..a5d4cf0aa03e 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -245,8 +245,8 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop,
245 * create_image - Create a hibernation image. 245 * create_image - Create a hibernation image.
246 * @platform_mode: Whether or not to use the platform driver. 246 * @platform_mode: Whether or not to use the platform driver.
247 * 247 *
248 * Execute device drivers' .freeze_noirq() callbacks, create a hibernation image 248 * Execute device drivers' "late" and "noirq" freeze callbacks, create a
249 * and execute the drivers' .thaw_noirq() callbacks. 249 * hibernation image and run the drivers' "noirq" and "early" thaw callbacks.
250 * 250 *
251 * Control reappears in this routine after the subsequent restore. 251 * Control reappears in this routine after the subsequent restore.
252 */ 252 */
@@ -254,7 +254,7 @@ static int create_image(int platform_mode)
254{ 254{
255 int error; 255 int error;
256 256
257 error = dpm_suspend_noirq(PMSG_FREEZE); 257 error = dpm_suspend_end(PMSG_FREEZE);
258 if (error) { 258 if (error) {
259 printk(KERN_ERR "PM: Some devices failed to power down, " 259 printk(KERN_ERR "PM: Some devices failed to power down, "
260 "aborting hibernation\n"); 260 "aborting hibernation\n");
@@ -306,7 +306,7 @@ static int create_image(int platform_mode)
306 Platform_finish: 306 Platform_finish:
307 platform_finish(platform_mode); 307 platform_finish(platform_mode);
308 308
309 dpm_resume_noirq(in_suspend ? 309 dpm_resume_start(in_suspend ?
310 (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); 310 (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
311 311
312 return error; 312 return error;
@@ -394,16 +394,16 @@ int hibernation_snapshot(int platform_mode)
394 * resume_target_kernel - Restore system state from a hibernation image. 394 * resume_target_kernel - Restore system state from a hibernation image.
395 * @platform_mode: Whether or not to use the platform driver. 395 * @platform_mode: Whether or not to use the platform driver.
396 * 396 *
397 * Execute device drivers' .freeze_noirq() callbacks, restore the contents of 397 * Execute device drivers' "noirq" and "late" freeze callbacks, restore the
398 * highmem that have not been restored yet from the image and run the low-level 398 * contents of highmem that have not been restored yet from the image and run
399 * code that will restore the remaining contents of memory and switch to the 399 * the low-level code that will restore the remaining contents of memory and
400 * just restored target kernel. 400 * switch to the just restored target kernel.
401 */ 401 */
402static int resume_target_kernel(bool platform_mode) 402static int resume_target_kernel(bool platform_mode)
403{ 403{
404 int error; 404 int error;
405 405
406 error = dpm_suspend_noirq(PMSG_QUIESCE); 406 error = dpm_suspend_end(PMSG_QUIESCE);
407 if (error) { 407 if (error) {
408 printk(KERN_ERR "PM: Some devices failed to power down, " 408 printk(KERN_ERR "PM: Some devices failed to power down, "
409 "aborting resume\n"); 409 "aborting resume\n");
@@ -460,7 +460,7 @@ static int resume_target_kernel(bool platform_mode)
460 Cleanup: 460 Cleanup:
461 platform_restore_cleanup(platform_mode); 461 platform_restore_cleanup(platform_mode);
462 462
463 dpm_resume_noirq(PMSG_RECOVER); 463 dpm_resume_start(PMSG_RECOVER);
464 464
465 return error; 465 return error;
466} 466}
@@ -518,7 +518,7 @@ int hibernation_platform_enter(void)
518 goto Resume_devices; 518 goto Resume_devices;
519 } 519 }
520 520
521 error = dpm_suspend_noirq(PMSG_HIBERNATE); 521 error = dpm_suspend_end(PMSG_HIBERNATE);
522 if (error) 522 if (error)
523 goto Resume_devices; 523 goto Resume_devices;
524 524
@@ -549,7 +549,7 @@ int hibernation_platform_enter(void)
549 Platform_finish: 549 Platform_finish:
550 hibernation_ops->finish(); 550 hibernation_ops->finish();
551 551
552 dpm_resume_noirq(PMSG_RESTORE); 552 dpm_resume_start(PMSG_RESTORE);
553 553
554 Resume_devices: 554 Resume_devices:
555 entering_platform_hibernation = false; 555 entering_platform_hibernation = false;