diff options
Diffstat (limited to 'kernel/power/hibernate.c')
-rw-r--r-- | kernel/power/hibernate.c | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 8f7b1db1ece1..1c53f7fad5f7 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/reboot.h> | 14 | #include <linux/reboot.h> |
15 | #include <linux/string.h> | 15 | #include <linux/string.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/async.h> | ||
17 | #include <linux/kmod.h> | 18 | #include <linux/kmod.h> |
18 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
19 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
@@ -29,12 +30,14 @@ | |||
29 | #include "power.h" | 30 | #include "power.h" |
30 | 31 | ||
31 | 32 | ||
32 | static int nocompress = 0; | 33 | static int nocompress; |
33 | static int noresume = 0; | 34 | static int noresume; |
35 | static int resume_wait; | ||
36 | static int resume_delay; | ||
34 | static char resume_file[256] = CONFIG_PM_STD_PARTITION; | 37 | static char resume_file[256] = CONFIG_PM_STD_PARTITION; |
35 | dev_t swsusp_resume_device; | 38 | dev_t swsusp_resume_device; |
36 | sector_t swsusp_resume_block; | 39 | sector_t swsusp_resume_block; |
37 | int in_suspend __nosavedata = 0; | 40 | int in_suspend __nosavedata; |
38 | 41 | ||
39 | enum { | 42 | enum { |
40 | HIBERNATION_INVALID, | 43 | HIBERNATION_INVALID, |
@@ -334,13 +337,17 @@ int hibernation_snapshot(int platform_mode) | |||
334 | if (error) | 337 | if (error) |
335 | goto Close; | 338 | goto Close; |
336 | 339 | ||
337 | error = dpm_prepare(PMSG_FREEZE); | ||
338 | if (error) | ||
339 | goto Complete_devices; | ||
340 | |||
341 | /* Preallocate image memory before shutting down devices. */ | 340 | /* Preallocate image memory before shutting down devices. */ |
342 | error = hibernate_preallocate_memory(); | 341 | error = hibernate_preallocate_memory(); |
343 | if (error) | 342 | if (error) |
343 | goto Close; | ||
344 | |||
345 | error = freeze_kernel_threads(); | ||
346 | if (error) | ||
347 | goto Close; | ||
348 | |||
349 | error = dpm_prepare(PMSG_FREEZE); | ||
350 | if (error) | ||
344 | goto Complete_devices; | 351 | goto Complete_devices; |
345 | 352 | ||
346 | suspend_console(); | 353 | suspend_console(); |
@@ -463,7 +470,7 @@ static int resume_target_kernel(bool platform_mode) | |||
463 | * @platform_mode: If set, use platform driver to prepare for the transition. | 470 | * @platform_mode: If set, use platform driver to prepare for the transition. |
464 | * | 471 | * |
465 | * This routine must be called with pm_mutex held. If it is successful, control | 472 | * This routine must be called with pm_mutex held. If it is successful, control |
466 | * reappears in the restored target kernel in hibernation_snaphot(). | 473 | * reappears in the restored target kernel in hibernation_snapshot(). |
467 | */ | 474 | */ |
468 | int hibernation_restore(int platform_mode) | 475 | int hibernation_restore(int platform_mode) |
469 | { | 476 | { |
@@ -650,6 +657,9 @@ int hibernate(void) | |||
650 | flags |= SF_PLATFORM_MODE; | 657 | flags |= SF_PLATFORM_MODE; |
651 | if (nocompress) | 658 | if (nocompress) |
652 | flags |= SF_NOCOMPRESS_MODE; | 659 | flags |= SF_NOCOMPRESS_MODE; |
660 | else | ||
661 | flags |= SF_CRC32_MODE; | ||
662 | |||
653 | pr_debug("PM: writing image.\n"); | 663 | pr_debug("PM: writing image.\n"); |
654 | error = swsusp_write(flags); | 664 | error = swsusp_write(flags); |
655 | swsusp_free(); | 665 | swsusp_free(); |
@@ -724,6 +734,12 @@ static int software_resume(void) | |||
724 | 734 | ||
725 | pr_debug("PM: Checking hibernation image partition %s\n", resume_file); | 735 | pr_debug("PM: Checking hibernation image partition %s\n", resume_file); |
726 | 736 | ||
737 | if (resume_delay) { | ||
738 | printk(KERN_INFO "Waiting %dsec before reading resume device...\n", | ||
739 | resume_delay); | ||
740 | ssleep(resume_delay); | ||
741 | } | ||
742 | |||
727 | /* Check if the device is there */ | 743 | /* Check if the device is there */ |
728 | swsusp_resume_device = name_to_dev_t(resume_file); | 744 | swsusp_resume_device = name_to_dev_t(resume_file); |
729 | if (!swsusp_resume_device) { | 745 | if (!swsusp_resume_device) { |
@@ -732,6 +748,13 @@ static int software_resume(void) | |||
732 | * to wait for this to finish. | 748 | * to wait for this to finish. |
733 | */ | 749 | */ |
734 | wait_for_device_probe(); | 750 | wait_for_device_probe(); |
751 | |||
752 | if (resume_wait) { | ||
753 | while ((swsusp_resume_device = name_to_dev_t(resume_file)) == 0) | ||
754 | msleep(10); | ||
755 | async_synchronize_full(); | ||
756 | } | ||
757 | |||
735 | /* | 758 | /* |
736 | * We can't depend on SCSI devices being available after loading | 759 | * We can't depend on SCSI devices being available after loading |
737 | * one of their modules until scsi_complete_async_scans() is | 760 | * one of their modules until scsi_complete_async_scans() is |
@@ -1060,7 +1083,21 @@ static int __init noresume_setup(char *str) | |||
1060 | return 1; | 1083 | return 1; |
1061 | } | 1084 | } |
1062 | 1085 | ||
1086 | static int __init resumewait_setup(char *str) | ||
1087 | { | ||
1088 | resume_wait = 1; | ||
1089 | return 1; | ||
1090 | } | ||
1091 | |||
1092 | static int __init resumedelay_setup(char *str) | ||
1093 | { | ||
1094 | resume_delay = simple_strtoul(str, NULL, 0); | ||
1095 | return 1; | ||
1096 | } | ||
1097 | |||
1063 | __setup("noresume", noresume_setup); | 1098 | __setup("noresume", noresume_setup); |
1064 | __setup("resume_offset=", resume_offset_setup); | 1099 | __setup("resume_offset=", resume_offset_setup); |
1065 | __setup("resume=", resume_setup); | 1100 | __setup("resume=", resume_setup); |
1066 | __setup("hibernate=", hibernate_setup); | 1101 | __setup("hibernate=", hibernate_setup); |
1102 | __setup("resumewait", resumewait_setup); | ||
1103 | __setup("resumedelay=", resumedelay_setup); | ||