diff options
Diffstat (limited to 'kernel/power/disk.c')
-rw-r--r-- | kernel/power/disk.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 45e8541ab7e3..4a4a206b1979 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -71,6 +71,14 @@ void hibernation_set_ops(struct platform_hibernation_ops *ops) | |||
71 | mutex_unlock(&pm_mutex); | 71 | mutex_unlock(&pm_mutex); |
72 | } | 72 | } |
73 | 73 | ||
74 | static bool entering_platform_hibernation; | ||
75 | |||
76 | bool system_entering_hibernation(void) | ||
77 | { | ||
78 | return entering_platform_hibernation; | ||
79 | } | ||
80 | EXPORT_SYMBOL(system_entering_hibernation); | ||
81 | |||
74 | #ifdef CONFIG_PM_DEBUG | 82 | #ifdef CONFIG_PM_DEBUG |
75 | static void hibernation_debug_sleep(void) | 83 | static void hibernation_debug_sleep(void) |
76 | { | 84 | { |
@@ -219,6 +227,12 @@ static int create_image(int platform_mode) | |||
219 | "aborting hibernation\n"); | 227 | "aborting hibernation\n"); |
220 | goto Enable_irqs; | 228 | goto Enable_irqs; |
221 | } | 229 | } |
230 | sysdev_suspend(PMSG_FREEZE); | ||
231 | if (error) { | ||
232 | printk(KERN_ERR "PM: Some devices failed to power down, " | ||
233 | "aborting hibernation\n"); | ||
234 | goto Power_up_devices; | ||
235 | } | ||
222 | 236 | ||
223 | if (hibernation_test(TEST_CORE)) | 237 | if (hibernation_test(TEST_CORE)) |
224 | goto Power_up; | 238 | goto Power_up; |
@@ -234,9 +248,11 @@ static int create_image(int platform_mode) | |||
234 | if (!in_suspend) | 248 | if (!in_suspend) |
235 | platform_leave(platform_mode); | 249 | platform_leave(platform_mode); |
236 | Power_up: | 250 | Power_up: |
251 | sysdev_resume(); | ||
237 | /* NOTE: device_power_up() is just a resume() for devices | 252 | /* NOTE: device_power_up() is just a resume() for devices |
238 | * that suspended with irqs off ... no overall powerup. | 253 | * that suspended with irqs off ... no overall powerup. |
239 | */ | 254 | */ |
255 | Power_up_devices: | ||
240 | device_power_up(in_suspend ? | 256 | device_power_up(in_suspend ? |
241 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 257 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
242 | Enable_irqs: | 258 | Enable_irqs: |
@@ -327,6 +343,7 @@ static int resume_target_kernel(void) | |||
327 | "aborting resume\n"); | 343 | "aborting resume\n"); |
328 | goto Enable_irqs; | 344 | goto Enable_irqs; |
329 | } | 345 | } |
346 | sysdev_suspend(PMSG_QUIESCE); | ||
330 | /* We'll ignore saved state, but this gets preempt count (etc) right */ | 347 | /* We'll ignore saved state, but this gets preempt count (etc) right */ |
331 | save_processor_state(); | 348 | save_processor_state(); |
332 | error = restore_highmem(); | 349 | error = restore_highmem(); |
@@ -349,6 +366,7 @@ static int resume_target_kernel(void) | |||
349 | swsusp_free(); | 366 | swsusp_free(); |
350 | restore_processor_state(); | 367 | restore_processor_state(); |
351 | touch_softlockup_watchdog(); | 368 | touch_softlockup_watchdog(); |
369 | sysdev_resume(); | ||
352 | device_power_up(PMSG_RECOVER); | 370 | device_power_up(PMSG_RECOVER); |
353 | Enable_irqs: | 371 | Enable_irqs: |
354 | local_irq_enable(); | 372 | local_irq_enable(); |
@@ -411,6 +429,7 @@ int hibernation_platform_enter(void) | |||
411 | if (error) | 429 | if (error) |
412 | goto Close; | 430 | goto Close; |
413 | 431 | ||
432 | entering_platform_hibernation = true; | ||
414 | suspend_console(); | 433 | suspend_console(); |
415 | error = device_suspend(PMSG_HIBERNATE); | 434 | error = device_suspend(PMSG_HIBERNATE); |
416 | if (error) { | 435 | if (error) { |
@@ -431,6 +450,7 @@ int hibernation_platform_enter(void) | |||
431 | local_irq_disable(); | 450 | local_irq_disable(); |
432 | error = device_power_down(PMSG_HIBERNATE); | 451 | error = device_power_down(PMSG_HIBERNATE); |
433 | if (!error) { | 452 | if (!error) { |
453 | sysdev_suspend(PMSG_HIBERNATE); | ||
434 | hibernation_ops->enter(); | 454 | hibernation_ops->enter(); |
435 | /* We should never get here */ | 455 | /* We should never get here */ |
436 | while (1); | 456 | while (1); |
@@ -445,6 +465,7 @@ int hibernation_platform_enter(void) | |||
445 | Finish: | 465 | Finish: |
446 | hibernation_ops->finish(); | 466 | hibernation_ops->finish(); |
447 | Resume_devices: | 467 | Resume_devices: |
468 | entering_platform_hibernation = false; | ||
448 | device_resume(PMSG_RESTORE); | 469 | device_resume(PMSG_RESTORE); |
449 | resume_console(); | 470 | resume_console(); |
450 | Close: | 471 | Close: |
@@ -585,6 +606,12 @@ static int software_resume(void) | |||
585 | unsigned int flags; | 606 | unsigned int flags; |
586 | 607 | ||
587 | /* | 608 | /* |
609 | * If the user said "noresume".. bail out early. | ||
610 | */ | ||
611 | if (noresume) | ||
612 | return 0; | ||
613 | |||
614 | /* | ||
588 | * name_to_dev_t() below takes a sysfs buffer mutex when sysfs | 615 | * name_to_dev_t() below takes a sysfs buffer mutex when sysfs |
589 | * is configured into the kernel. Since the regular hibernate | 616 | * is configured into the kernel. Since the regular hibernate |
590 | * trigger path is via sysfs which takes a buffer mutex before | 617 | * trigger path is via sysfs which takes a buffer mutex before |
@@ -600,6 +627,11 @@ static int software_resume(void) | |||
600 | mutex_unlock(&pm_mutex); | 627 | mutex_unlock(&pm_mutex); |
601 | return -ENOENT; | 628 | return -ENOENT; |
602 | } | 629 | } |
630 | /* | ||
631 | * Some device discovery might still be in progress; we need | ||
632 | * to wait for this to finish. | ||
633 | */ | ||
634 | wait_for_device_probe(); | ||
603 | swsusp_resume_device = name_to_dev_t(resume_file); | 635 | swsusp_resume_device = name_to_dev_t(resume_file); |
604 | pr_debug("PM: Resume from partition %s\n", resume_file); | 636 | pr_debug("PM: Resume from partition %s\n", resume_file); |
605 | } else { | 637 | } else { |