diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-01-09 02:38:23 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-01-09 02:38:23 -0500 |
commit | da733563be5a9da26fe81d9f007262d00b846e22 (patch) | |
tree | db28291df94a2043af2123911984c5c173da4e6f /kernel/power/hibernate.c | |
parent | 6ccbcf2cb41131f8d56ef0723bf3f7c1f8486076 (diff) | |
parent | dab78d7924598ea4031663dd10db814e2e324928 (diff) |
Merge branch 'next' into for-linus
Diffstat (limited to 'kernel/power/hibernate.c')
-rw-r--r-- | kernel/power/hibernate.c | 77 |
1 files changed, 63 insertions, 14 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 8f7b1db1ece1..196c01268ebd 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -9,11 +9,13 @@ | |||
9 | * This file is released under the GPLv2. | 9 | * This file is released under the GPLv2. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/export.h> | ||
12 | #include <linux/suspend.h> | 13 | #include <linux/suspend.h> |
13 | #include <linux/syscalls.h> | 14 | #include <linux/syscalls.h> |
14 | #include <linux/reboot.h> | 15 | #include <linux/reboot.h> |
15 | #include <linux/string.h> | 16 | #include <linux/string.h> |
16 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/async.h> | ||
17 | #include <linux/kmod.h> | 19 | #include <linux/kmod.h> |
18 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
19 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
@@ -29,12 +31,14 @@ | |||
29 | #include "power.h" | 31 | #include "power.h" |
30 | 32 | ||
31 | 33 | ||
32 | static int nocompress = 0; | 34 | static int nocompress; |
33 | static int noresume = 0; | 35 | static int noresume; |
36 | static int resume_wait; | ||
37 | static int resume_delay; | ||
34 | static char resume_file[256] = CONFIG_PM_STD_PARTITION; | 38 | static char resume_file[256] = CONFIG_PM_STD_PARTITION; |
35 | dev_t swsusp_resume_device; | 39 | dev_t swsusp_resume_device; |
36 | sector_t swsusp_resume_block; | 40 | sector_t swsusp_resume_block; |
37 | int in_suspend __nosavedata = 0; | 41 | int in_suspend __nosavedata; |
38 | 42 | ||
39 | enum { | 43 | enum { |
40 | HIBERNATION_INVALID, | 44 | HIBERNATION_INVALID, |
@@ -51,6 +55,8 @@ enum { | |||
51 | 55 | ||
52 | static int hibernation_mode = HIBERNATION_SHUTDOWN; | 56 | static int hibernation_mode = HIBERNATION_SHUTDOWN; |
53 | 57 | ||
58 | static bool freezer_test_done; | ||
59 | |||
54 | static const struct platform_hibernation_ops *hibernation_ops; | 60 | static const struct platform_hibernation_ops *hibernation_ops; |
55 | 61 | ||
56 | /** | 62 | /** |
@@ -334,13 +340,28 @@ int hibernation_snapshot(int platform_mode) | |||
334 | if (error) | 340 | if (error) |
335 | goto Close; | 341 | goto Close; |
336 | 342 | ||
337 | error = dpm_prepare(PMSG_FREEZE); | ||
338 | if (error) | ||
339 | goto Complete_devices; | ||
340 | |||
341 | /* Preallocate image memory before shutting down devices. */ | 343 | /* Preallocate image memory before shutting down devices. */ |
342 | error = hibernate_preallocate_memory(); | 344 | error = hibernate_preallocate_memory(); |
343 | if (error) | 345 | if (error) |
346 | goto Close; | ||
347 | |||
348 | error = freeze_kernel_threads(); | ||
349 | if (error) | ||
350 | goto Close; | ||
351 | |||
352 | if (hibernation_test(TEST_FREEZER) || | ||
353 | hibernation_testmode(HIBERNATION_TESTPROC)) { | ||
354 | |||
355 | /* | ||
356 | * Indicate to the caller that we are returning due to a | ||
357 | * successful freezer test. | ||
358 | */ | ||
359 | freezer_test_done = true; | ||
360 | goto Close; | ||
361 | } | ||
362 | |||
363 | error = dpm_prepare(PMSG_FREEZE); | ||
364 | if (error) | ||
344 | goto Complete_devices; | 365 | goto Complete_devices; |
345 | 366 | ||
346 | suspend_console(); | 367 | suspend_console(); |
@@ -463,7 +484,7 @@ static int resume_target_kernel(bool platform_mode) | |||
463 | * @platform_mode: If set, use platform driver to prepare for the transition. | 484 | * @platform_mode: If set, use platform driver to prepare for the transition. |
464 | * | 485 | * |
465 | * This routine must be called with pm_mutex held. If it is successful, control | 486 | * This routine must be called with pm_mutex held. If it is successful, control |
466 | * reappears in the restored target kernel in hibernation_snaphot(). | 487 | * reappears in the restored target kernel in hibernation_snapshot(). |
467 | */ | 488 | */ |
468 | int hibernation_restore(int platform_mode) | 489 | int hibernation_restore(int platform_mode) |
469 | { | 490 | { |
@@ -633,15 +654,13 @@ int hibernate(void) | |||
633 | if (error) | 654 | if (error) |
634 | goto Finish; | 655 | goto Finish; |
635 | 656 | ||
636 | if (hibernation_test(TEST_FREEZER)) | ||
637 | goto Thaw; | ||
638 | |||
639 | if (hibernation_testmode(HIBERNATION_TESTPROC)) | ||
640 | goto Thaw; | ||
641 | |||
642 | error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); | 657 | error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); |
643 | if (error) | 658 | if (error) |
644 | goto Thaw; | 659 | goto Thaw; |
660 | if (freezer_test_done) { | ||
661 | freezer_test_done = false; | ||
662 | goto Thaw; | ||
663 | } | ||
645 | 664 | ||
646 | if (in_suspend) { | 665 | if (in_suspend) { |
647 | unsigned int flags = 0; | 666 | unsigned int flags = 0; |
@@ -650,6 +669,9 @@ int hibernate(void) | |||
650 | flags |= SF_PLATFORM_MODE; | 669 | flags |= SF_PLATFORM_MODE; |
651 | if (nocompress) | 670 | if (nocompress) |
652 | flags |= SF_NOCOMPRESS_MODE; | 671 | flags |= SF_NOCOMPRESS_MODE; |
672 | else | ||
673 | flags |= SF_CRC32_MODE; | ||
674 | |||
653 | pr_debug("PM: writing image.\n"); | 675 | pr_debug("PM: writing image.\n"); |
654 | error = swsusp_write(flags); | 676 | error = swsusp_write(flags); |
655 | swsusp_free(); | 677 | swsusp_free(); |
@@ -724,6 +746,12 @@ static int software_resume(void) | |||
724 | 746 | ||
725 | pr_debug("PM: Checking hibernation image partition %s\n", resume_file); | 747 | pr_debug("PM: Checking hibernation image partition %s\n", resume_file); |
726 | 748 | ||
749 | if (resume_delay) { | ||
750 | printk(KERN_INFO "Waiting %dsec before reading resume device...\n", | ||
751 | resume_delay); | ||
752 | ssleep(resume_delay); | ||
753 | } | ||
754 | |||
727 | /* Check if the device is there */ | 755 | /* Check if the device is there */ |
728 | swsusp_resume_device = name_to_dev_t(resume_file); | 756 | swsusp_resume_device = name_to_dev_t(resume_file); |
729 | if (!swsusp_resume_device) { | 757 | if (!swsusp_resume_device) { |
@@ -732,6 +760,13 @@ static int software_resume(void) | |||
732 | * to wait for this to finish. | 760 | * to wait for this to finish. |
733 | */ | 761 | */ |
734 | wait_for_device_probe(); | 762 | wait_for_device_probe(); |
763 | |||
764 | if (resume_wait) { | ||
765 | while ((swsusp_resume_device = name_to_dev_t(resume_file)) == 0) | ||
766 | msleep(10); | ||
767 | async_synchronize_full(); | ||
768 | } | ||
769 | |||
735 | /* | 770 | /* |
736 | * We can't depend on SCSI devices being available after loading | 771 | * We can't depend on SCSI devices being available after loading |
737 | * one of their modules until scsi_complete_async_scans() is | 772 | * one of their modules until scsi_complete_async_scans() is |
@@ -1060,7 +1095,21 @@ static int __init noresume_setup(char *str) | |||
1060 | return 1; | 1095 | return 1; |
1061 | } | 1096 | } |
1062 | 1097 | ||
1098 | static int __init resumewait_setup(char *str) | ||
1099 | { | ||
1100 | resume_wait = 1; | ||
1101 | return 1; | ||
1102 | } | ||
1103 | |||
1104 | static int __init resumedelay_setup(char *str) | ||
1105 | { | ||
1106 | resume_delay = simple_strtoul(str, NULL, 0); | ||
1107 | return 1; | ||
1108 | } | ||
1109 | |||
1063 | __setup("noresume", noresume_setup); | 1110 | __setup("noresume", noresume_setup); |
1064 | __setup("resume_offset=", resume_offset_setup); | 1111 | __setup("resume_offset=", resume_offset_setup); |
1065 | __setup("resume=", resume_setup); | 1112 | __setup("resume=", resume_setup); |
1066 | __setup("hibernate=", hibernate_setup); | 1113 | __setup("hibernate=", hibernate_setup); |
1114 | __setup("resumewait", resumewait_setup); | ||
1115 | __setup("resumedelay=", resumedelay_setup); | ||