aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/hibernate.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2012-01-09 02:38:23 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-01-09 02:38:23 -0500
commitda733563be5a9da26fe81d9f007262d00b846e22 (patch)
treedb28291df94a2043af2123911984c5c173da4e6f /kernel/power/hibernate.c
parent6ccbcf2cb41131f8d56ef0723bf3f7c1f8486076 (diff)
parentdab78d7924598ea4031663dd10db814e2e324928 (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'kernel/power/hibernate.c')
-rw-r--r--kernel/power/hibernate.c77
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
32static int nocompress = 0; 34static int nocompress;
33static int noresume = 0; 35static int noresume;
36static int resume_wait;
37static int resume_delay;
34static char resume_file[256] = CONFIG_PM_STD_PARTITION; 38static char resume_file[256] = CONFIG_PM_STD_PARTITION;
35dev_t swsusp_resume_device; 39dev_t swsusp_resume_device;
36sector_t swsusp_resume_block; 40sector_t swsusp_resume_block;
37int in_suspend __nosavedata = 0; 41int in_suspend __nosavedata;
38 42
39enum { 43enum {
40 HIBERNATION_INVALID, 44 HIBERNATION_INVALID,
@@ -51,6 +55,8 @@ enum {
51 55
52static int hibernation_mode = HIBERNATION_SHUTDOWN; 56static int hibernation_mode = HIBERNATION_SHUTDOWN;
53 57
58static bool freezer_test_done;
59
54static const struct platform_hibernation_ops *hibernation_ops; 60static 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 */
468int hibernation_restore(int platform_mode) 489int 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
1098static int __init resumewait_setup(char *str)
1099{
1100 resume_wait = 1;
1101 return 1;
1102}
1103
1104static 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);