diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-08 16:10:57 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-08 16:10:57 -0500 |
commit | eb59c505f8a5906ad2e053d14fab50eb8574fd6f (patch) | |
tree | c6e875adc12b481b916e847e8f80b8881a0fb02c /kernel/power/hibernate.c | |
parent | 1619ed8f60959829d070d8f39cd2f8ca0e7135ce (diff) | |
parent | c233523b3d392e530033a7587d7970dc62a02361 (diff) |
Merge branch 'pm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
* 'pm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (76 commits)
PM / Hibernate: Implement compat_ioctl for /dev/snapshot
PM / Freezer: fix return value of freezable_schedule_timeout_killable()
PM / shmobile: Allow the A4R domain to be turned off at run time
PM / input / touchscreen: Make st1232 use device PM QoS constraints
PM / QoS: Introduce dev_pm_qos_add_ancestor_request()
PM / shmobile: Remove the stay_on flag from SH7372's PM domains
PM / shmobile: Don't include SH7372's INTCS in syscore suspend/resume
PM / shmobile: Add support for the sh7372 A4S power domain / sleep mode
PM: Drop generic_subsys_pm_ops
PM / Sleep: Remove forward-only callbacks from AMBA bus type
PM / Sleep: Remove forward-only callbacks from platform bus type
PM: Run the driver callback directly if the subsystem one is not there
PM / Sleep: Make pm_op() and pm_noirq_op() return callback pointers
PM/Devfreq: Add Exynos4-bus device DVFS driver for Exynos4210/4212/4412.
PM / Sleep: Merge internal functions in generic_ops.c
PM / Sleep: Simplify generic system suspend callbacks
PM / Hibernate: Remove deprecated hibernation snapshot ioctls
PM / Sleep: Fix freezer failures due to racy usermodehelper_is_disabled()
ARM: S3C64XX: Implement basic power domain support
PM / shmobile: Use common always on power domain governor
...
Fix up trivial conflict in fs/xfs/xfs_buf.c due to removal of unused
XBT_FORCE_SLEEP bit
Diffstat (limited to 'kernel/power/hibernate.c')
-rw-r--r-- | kernel/power/hibernate.c | 92 |
1 files changed, 27 insertions, 65 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index a6b0503574ee..6d6d28870335 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -43,8 +43,6 @@ int in_suspend __nosavedata; | |||
43 | enum { | 43 | enum { |
44 | HIBERNATION_INVALID, | 44 | HIBERNATION_INVALID, |
45 | HIBERNATION_PLATFORM, | 45 | HIBERNATION_PLATFORM, |
46 | HIBERNATION_TEST, | ||
47 | HIBERNATION_TESTPROC, | ||
48 | HIBERNATION_SHUTDOWN, | 46 | HIBERNATION_SHUTDOWN, |
49 | HIBERNATION_REBOOT, | 47 | HIBERNATION_REBOOT, |
50 | /* keep last */ | 48 | /* keep last */ |
@@ -55,7 +53,7 @@ enum { | |||
55 | 53 | ||
56 | static int hibernation_mode = HIBERNATION_SHUTDOWN; | 54 | static int hibernation_mode = HIBERNATION_SHUTDOWN; |
57 | 55 | ||
58 | static bool freezer_test_done; | 56 | bool freezer_test_done; |
59 | 57 | ||
60 | static const struct platform_hibernation_ops *hibernation_ops; | 58 | static const struct platform_hibernation_ops *hibernation_ops; |
61 | 59 | ||
@@ -71,14 +69,14 @@ void hibernation_set_ops(const struct platform_hibernation_ops *ops) | |||
71 | WARN_ON(1); | 69 | WARN_ON(1); |
72 | return; | 70 | return; |
73 | } | 71 | } |
74 | mutex_lock(&pm_mutex); | 72 | lock_system_sleep(); |
75 | hibernation_ops = ops; | 73 | hibernation_ops = ops; |
76 | if (ops) | 74 | if (ops) |
77 | hibernation_mode = HIBERNATION_PLATFORM; | 75 | hibernation_mode = HIBERNATION_PLATFORM; |
78 | else if (hibernation_mode == HIBERNATION_PLATFORM) | 76 | else if (hibernation_mode == HIBERNATION_PLATFORM) |
79 | hibernation_mode = HIBERNATION_SHUTDOWN; | 77 | hibernation_mode = HIBERNATION_SHUTDOWN; |
80 | 78 | ||
81 | mutex_unlock(&pm_mutex); | 79 | unlock_system_sleep(); |
82 | } | 80 | } |
83 | 81 | ||
84 | static bool entering_platform_hibernation; | 82 | static bool entering_platform_hibernation; |
@@ -96,15 +94,6 @@ static void hibernation_debug_sleep(void) | |||
96 | mdelay(5000); | 94 | mdelay(5000); |
97 | } | 95 | } |
98 | 96 | ||
99 | static int hibernation_testmode(int mode) | ||
100 | { | ||
101 | if (hibernation_mode == mode) { | ||
102 | hibernation_debug_sleep(); | ||
103 | return 1; | ||
104 | } | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int hibernation_test(int level) | 97 | static int hibernation_test(int level) |
109 | { | 98 | { |
110 | if (pm_test_level == level) { | 99 | if (pm_test_level == level) { |
@@ -114,7 +103,6 @@ static int hibernation_test(int level) | |||
114 | return 0; | 103 | return 0; |
115 | } | 104 | } |
116 | #else /* !CONFIG_PM_DEBUG */ | 105 | #else /* !CONFIG_PM_DEBUG */ |
117 | static int hibernation_testmode(int mode) { return 0; } | ||
118 | static int hibernation_test(int level) { return 0; } | 106 | static int hibernation_test(int level) { return 0; } |
119 | #endif /* !CONFIG_PM_DEBUG */ | 107 | #endif /* !CONFIG_PM_DEBUG */ |
120 | 108 | ||
@@ -278,8 +266,7 @@ static int create_image(int platform_mode) | |||
278 | goto Platform_finish; | 266 | goto Platform_finish; |
279 | 267 | ||
280 | error = disable_nonboot_cpus(); | 268 | error = disable_nonboot_cpus(); |
281 | if (error || hibernation_test(TEST_CPUS) | 269 | if (error || hibernation_test(TEST_CPUS)) |
282 | || hibernation_testmode(HIBERNATION_TEST)) | ||
283 | goto Enable_cpus; | 270 | goto Enable_cpus; |
284 | 271 | ||
285 | local_irq_disable(); | 272 | local_irq_disable(); |
@@ -333,7 +320,7 @@ static int create_image(int platform_mode) | |||
333 | */ | 320 | */ |
334 | int hibernation_snapshot(int platform_mode) | 321 | int hibernation_snapshot(int platform_mode) |
335 | { | 322 | { |
336 | pm_message_t msg = PMSG_RECOVER; | 323 | pm_message_t msg; |
337 | int error; | 324 | int error; |
338 | 325 | ||
339 | error = platform_begin(platform_mode); | 326 | error = platform_begin(platform_mode); |
@@ -349,8 +336,7 @@ int hibernation_snapshot(int platform_mode) | |||
349 | if (error) | 336 | if (error) |
350 | goto Cleanup; | 337 | goto Cleanup; |
351 | 338 | ||
352 | if (hibernation_test(TEST_FREEZER) || | 339 | if (hibernation_test(TEST_FREEZER)) { |
353 | hibernation_testmode(HIBERNATION_TESTPROC)) { | ||
354 | 340 | ||
355 | /* | 341 | /* |
356 | * Indicate to the caller that we are returning due to a | 342 | * Indicate to the caller that we are returning due to a |
@@ -362,26 +348,26 @@ int hibernation_snapshot(int platform_mode) | |||
362 | 348 | ||
363 | error = dpm_prepare(PMSG_FREEZE); | 349 | error = dpm_prepare(PMSG_FREEZE); |
364 | if (error) { | 350 | if (error) { |
365 | dpm_complete(msg); | 351 | dpm_complete(PMSG_RECOVER); |
366 | goto Cleanup; | 352 | goto Cleanup; |
367 | } | 353 | } |
368 | 354 | ||
369 | suspend_console(); | 355 | suspend_console(); |
370 | pm_restrict_gfp_mask(); | 356 | pm_restrict_gfp_mask(); |
357 | |||
371 | error = dpm_suspend(PMSG_FREEZE); | 358 | error = dpm_suspend(PMSG_FREEZE); |
372 | if (error) | ||
373 | goto Recover_platform; | ||
374 | 359 | ||
375 | if (hibernation_test(TEST_DEVICES)) | 360 | if (error || hibernation_test(TEST_DEVICES)) |
376 | goto Recover_platform; | 361 | platform_recover(platform_mode); |
362 | else | ||
363 | error = create_image(platform_mode); | ||
377 | 364 | ||
378 | error = create_image(platform_mode); | ||
379 | /* | 365 | /* |
380 | * Control returns here (1) after the image has been created or the | 366 | * In the case that we call create_image() above, the control |
367 | * returns here (1) after the image has been created or the | ||
381 | * image creation has failed and (2) after a successful restore. | 368 | * image creation has failed and (2) after a successful restore. |
382 | */ | 369 | */ |
383 | 370 | ||
384 | Resume_devices: | ||
385 | /* We may need to release the preallocated image pages here. */ | 371 | /* We may need to release the preallocated image pages here. */ |
386 | if (error || !in_suspend) | 372 | if (error || !in_suspend) |
387 | swsusp_free(); | 373 | swsusp_free(); |
@@ -399,10 +385,6 @@ int hibernation_snapshot(int platform_mode) | |||
399 | platform_end(platform_mode); | 385 | platform_end(platform_mode); |
400 | return error; | 386 | return error; |
401 | 387 | ||
402 | Recover_platform: | ||
403 | platform_recover(platform_mode); | ||
404 | goto Resume_devices; | ||
405 | |||
406 | Cleanup: | 388 | Cleanup: |
407 | swsusp_free(); | 389 | swsusp_free(); |
408 | goto Close; | 390 | goto Close; |
@@ -590,9 +572,6 @@ int hibernation_platform_enter(void) | |||
590 | static void power_down(void) | 572 | static void power_down(void) |
591 | { | 573 | { |
592 | switch (hibernation_mode) { | 574 | switch (hibernation_mode) { |
593 | case HIBERNATION_TEST: | ||
594 | case HIBERNATION_TESTPROC: | ||
595 | break; | ||
596 | case HIBERNATION_REBOOT: | 575 | case HIBERNATION_REBOOT: |
597 | kernel_restart(NULL); | 576 | kernel_restart(NULL); |
598 | break; | 577 | break; |
@@ -611,17 +590,6 @@ static void power_down(void) | |||
611 | while(1); | 590 | while(1); |
612 | } | 591 | } |
613 | 592 | ||
614 | static int prepare_processes(void) | ||
615 | { | ||
616 | int error = 0; | ||
617 | |||
618 | if (freeze_processes()) { | ||
619 | error = -EBUSY; | ||
620 | thaw_processes(); | ||
621 | } | ||
622 | return error; | ||
623 | } | ||
624 | |||
625 | /** | 593 | /** |
626 | * hibernate - Carry out system hibernation, including saving the image. | 594 | * hibernate - Carry out system hibernation, including saving the image. |
627 | */ | 595 | */ |
@@ -629,7 +597,7 @@ int hibernate(void) | |||
629 | { | 597 | { |
630 | int error; | 598 | int error; |
631 | 599 | ||
632 | mutex_lock(&pm_mutex); | 600 | lock_system_sleep(); |
633 | /* The snapshot device should not be opened while we're running */ | 601 | /* The snapshot device should not be opened while we're running */ |
634 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { | 602 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { |
635 | error = -EBUSY; | 603 | error = -EBUSY; |
@@ -654,7 +622,7 @@ int hibernate(void) | |||
654 | sys_sync(); | 622 | sys_sync(); |
655 | printk("done.\n"); | 623 | printk("done.\n"); |
656 | 624 | ||
657 | error = prepare_processes(); | 625 | error = freeze_processes(); |
658 | if (error) | 626 | if (error) |
659 | goto Finish; | 627 | goto Finish; |
660 | 628 | ||
@@ -697,7 +665,7 @@ int hibernate(void) | |||
697 | pm_restore_console(); | 665 | pm_restore_console(); |
698 | atomic_inc(&snapshot_device_available); | 666 | atomic_inc(&snapshot_device_available); |
699 | Unlock: | 667 | Unlock: |
700 | mutex_unlock(&pm_mutex); | 668 | unlock_system_sleep(); |
701 | return error; | 669 | return error; |
702 | } | 670 | } |
703 | 671 | ||
@@ -811,11 +779,13 @@ static int software_resume(void) | |||
811 | goto close_finish; | 779 | goto close_finish; |
812 | 780 | ||
813 | error = create_basic_memory_bitmaps(); | 781 | error = create_basic_memory_bitmaps(); |
814 | if (error) | 782 | if (error) { |
783 | usermodehelper_enable(); | ||
815 | goto close_finish; | 784 | goto close_finish; |
785 | } | ||
816 | 786 | ||
817 | pr_debug("PM: Preparing processes for restore.\n"); | 787 | pr_debug("PM: Preparing processes for restore.\n"); |
818 | error = prepare_processes(); | 788 | error = freeze_processes(); |
819 | if (error) { | 789 | if (error) { |
820 | swsusp_close(FMODE_READ); | 790 | swsusp_close(FMODE_READ); |
821 | goto Done; | 791 | goto Done; |
@@ -855,8 +825,6 @@ static const char * const hibernation_modes[] = { | |||
855 | [HIBERNATION_PLATFORM] = "platform", | 825 | [HIBERNATION_PLATFORM] = "platform", |
856 | [HIBERNATION_SHUTDOWN] = "shutdown", | 826 | [HIBERNATION_SHUTDOWN] = "shutdown", |
857 | [HIBERNATION_REBOOT] = "reboot", | 827 | [HIBERNATION_REBOOT] = "reboot", |
858 | [HIBERNATION_TEST] = "test", | ||
859 | [HIBERNATION_TESTPROC] = "testproc", | ||
860 | }; | 828 | }; |
861 | 829 | ||
862 | /* | 830 | /* |
@@ -865,17 +833,15 @@ static const char * const hibernation_modes[] = { | |||
865 | * Hibernation can be handled in several ways. There are a few different ways | 833 | * Hibernation can be handled in several ways. There are a few different ways |
866 | * to put the system into the sleep state: using the platform driver (e.g. ACPI | 834 | * to put the system into the sleep state: using the platform driver (e.g. ACPI |
867 | * or other hibernation_ops), powering it off or rebooting it (for testing | 835 | * or other hibernation_ops), powering it off or rebooting it (for testing |
868 | * mostly), or using one of the two available test modes. | 836 | * mostly). |
869 | * | 837 | * |
870 | * The sysfs file /sys/power/disk provides an interface for selecting the | 838 | * The sysfs file /sys/power/disk provides an interface for selecting the |
871 | * hibernation mode to use. Reading from this file causes the available modes | 839 | * hibernation mode to use. Reading from this file causes the available modes |
872 | * to be printed. There are 5 modes that can be supported: | 840 | * to be printed. There are 3 modes that can be supported: |
873 | * | 841 | * |
874 | * 'platform' | 842 | * 'platform' |
875 | * 'shutdown' | 843 | * 'shutdown' |
876 | * 'reboot' | 844 | * 'reboot' |
877 | * 'test' | ||
878 | * 'testproc' | ||
879 | * | 845 | * |
880 | * If a platform hibernation driver is in use, 'platform' will be supported | 846 | * If a platform hibernation driver is in use, 'platform' will be supported |
881 | * and will be used by default. Otherwise, 'shutdown' will be used by default. | 847 | * and will be used by default. Otherwise, 'shutdown' will be used by default. |
@@ -899,8 +865,6 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, | |||
899 | switch (i) { | 865 | switch (i) { |
900 | case HIBERNATION_SHUTDOWN: | 866 | case HIBERNATION_SHUTDOWN: |
901 | case HIBERNATION_REBOOT: | 867 | case HIBERNATION_REBOOT: |
902 | case HIBERNATION_TEST: | ||
903 | case HIBERNATION_TESTPROC: | ||
904 | break; | 868 | break; |
905 | case HIBERNATION_PLATFORM: | 869 | case HIBERNATION_PLATFORM: |
906 | if (hibernation_ops) | 870 | if (hibernation_ops) |
@@ -929,7 +893,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
929 | p = memchr(buf, '\n', n); | 893 | p = memchr(buf, '\n', n); |
930 | len = p ? p - buf : n; | 894 | len = p ? p - buf : n; |
931 | 895 | ||
932 | mutex_lock(&pm_mutex); | 896 | lock_system_sleep(); |
933 | for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { | 897 | for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { |
934 | if (len == strlen(hibernation_modes[i]) | 898 | if (len == strlen(hibernation_modes[i]) |
935 | && !strncmp(buf, hibernation_modes[i], len)) { | 899 | && !strncmp(buf, hibernation_modes[i], len)) { |
@@ -941,8 +905,6 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
941 | switch (mode) { | 905 | switch (mode) { |
942 | case HIBERNATION_SHUTDOWN: | 906 | case HIBERNATION_SHUTDOWN: |
943 | case HIBERNATION_REBOOT: | 907 | case HIBERNATION_REBOOT: |
944 | case HIBERNATION_TEST: | ||
945 | case HIBERNATION_TESTPROC: | ||
946 | hibernation_mode = mode; | 908 | hibernation_mode = mode; |
947 | break; | 909 | break; |
948 | case HIBERNATION_PLATFORM: | 910 | case HIBERNATION_PLATFORM: |
@@ -957,7 +919,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
957 | if (!error) | 919 | if (!error) |
958 | pr_debug("PM: Hibernation mode set to '%s'\n", | 920 | pr_debug("PM: Hibernation mode set to '%s'\n", |
959 | hibernation_modes[mode]); | 921 | hibernation_modes[mode]); |
960 | mutex_unlock(&pm_mutex); | 922 | unlock_system_sleep(); |
961 | return error ? error : n; | 923 | return error ? error : n; |
962 | } | 924 | } |
963 | 925 | ||
@@ -984,9 +946,9 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
984 | if (maj != MAJOR(res) || min != MINOR(res)) | 946 | if (maj != MAJOR(res) || min != MINOR(res)) |
985 | goto out; | 947 | goto out; |
986 | 948 | ||
987 | mutex_lock(&pm_mutex); | 949 | lock_system_sleep(); |
988 | swsusp_resume_device = res; | 950 | swsusp_resume_device = res; |
989 | mutex_unlock(&pm_mutex); | 951 | unlock_system_sleep(); |
990 | printk(KERN_INFO "PM: Starting manual resume from disk\n"); | 952 | printk(KERN_INFO "PM: Starting manual resume from disk\n"); |
991 | noresume = 0; | 953 | noresume = 0; |
992 | software_resume(); | 954 | software_resume(); |