diff options
Diffstat (limited to 'kernel/power/hibernate.c')
-rw-r--r-- | kernel/power/hibernate.c | 50 |
1 files changed, 42 insertions, 8 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 8b53db38a279..b26f5f1e773e 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Copyright (c) 2003 Open Source Development Lab | 5 | * Copyright (c) 2003 Open Source Development Lab |
6 | * Copyright (c) 2004 Pavel Machek <pavel@ucw.cz> | 6 | * Copyright (c) 2004 Pavel Machek <pavel@ucw.cz> |
7 | * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc. | 7 | * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc. |
8 | * Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com> | ||
8 | * | 9 | * |
9 | * This file is released under the GPLv2. | 10 | * This file is released under the GPLv2. |
10 | */ | 11 | */ |
@@ -27,7 +28,6 @@ | |||
27 | #include <linux/syscore_ops.h> | 28 | #include <linux/syscore_ops.h> |
28 | #include <linux/ctype.h> | 29 | #include <linux/ctype.h> |
29 | #include <linux/genhd.h> | 30 | #include <linux/genhd.h> |
30 | #include <scsi/scsi_scan.h> | ||
31 | 31 | ||
32 | #include "power.h" | 32 | #include "power.h" |
33 | 33 | ||
@@ -46,6 +46,9 @@ enum { | |||
46 | HIBERNATION_PLATFORM, | 46 | HIBERNATION_PLATFORM, |
47 | HIBERNATION_SHUTDOWN, | 47 | HIBERNATION_SHUTDOWN, |
48 | HIBERNATION_REBOOT, | 48 | HIBERNATION_REBOOT, |
49 | #ifdef CONFIG_SUSPEND | ||
50 | HIBERNATION_SUSPEND, | ||
51 | #endif | ||
49 | /* keep last */ | 52 | /* keep last */ |
50 | __HIBERNATION_AFTER_LAST | 53 | __HIBERNATION_AFTER_LAST |
51 | }; | 54 | }; |
@@ -354,6 +357,7 @@ int hibernation_snapshot(int platform_mode) | |||
354 | } | 357 | } |
355 | 358 | ||
356 | suspend_console(); | 359 | suspend_console(); |
360 | ftrace_stop(); | ||
357 | pm_restrict_gfp_mask(); | 361 | pm_restrict_gfp_mask(); |
358 | 362 | ||
359 | error = dpm_suspend(PMSG_FREEZE); | 363 | error = dpm_suspend(PMSG_FREEZE); |
@@ -379,6 +383,7 @@ int hibernation_snapshot(int platform_mode) | |||
379 | if (error || !in_suspend) | 383 | if (error || !in_suspend) |
380 | pm_restore_gfp_mask(); | 384 | pm_restore_gfp_mask(); |
381 | 385 | ||
386 | ftrace_start(); | ||
382 | resume_console(); | 387 | resume_console(); |
383 | dpm_complete(msg); | 388 | dpm_complete(msg); |
384 | 389 | ||
@@ -481,6 +486,7 @@ int hibernation_restore(int platform_mode) | |||
481 | 486 | ||
482 | pm_prepare_console(); | 487 | pm_prepare_console(); |
483 | suspend_console(); | 488 | suspend_console(); |
489 | ftrace_stop(); | ||
484 | pm_restrict_gfp_mask(); | 490 | pm_restrict_gfp_mask(); |
485 | error = dpm_suspend_start(PMSG_QUIESCE); | 491 | error = dpm_suspend_start(PMSG_QUIESCE); |
486 | if (!error) { | 492 | if (!error) { |
@@ -488,6 +494,7 @@ int hibernation_restore(int platform_mode) | |||
488 | dpm_resume_end(PMSG_RECOVER); | 494 | dpm_resume_end(PMSG_RECOVER); |
489 | } | 495 | } |
490 | pm_restore_gfp_mask(); | 496 | pm_restore_gfp_mask(); |
497 | ftrace_start(); | ||
491 | resume_console(); | 498 | resume_console(); |
492 | pm_restore_console(); | 499 | pm_restore_console(); |
493 | return error; | 500 | return error; |
@@ -514,6 +521,7 @@ int hibernation_platform_enter(void) | |||
514 | 521 | ||
515 | entering_platform_hibernation = true; | 522 | entering_platform_hibernation = true; |
516 | suspend_console(); | 523 | suspend_console(); |
524 | ftrace_stop(); | ||
517 | error = dpm_suspend_start(PMSG_HIBERNATE); | 525 | error = dpm_suspend_start(PMSG_HIBERNATE); |
518 | if (error) { | 526 | if (error) { |
519 | if (hibernation_ops->recover) | 527 | if (hibernation_ops->recover) |
@@ -557,6 +565,7 @@ int hibernation_platform_enter(void) | |||
557 | Resume_devices: | 565 | Resume_devices: |
558 | entering_platform_hibernation = false; | 566 | entering_platform_hibernation = false; |
559 | dpm_resume_end(PMSG_RESTORE); | 567 | dpm_resume_end(PMSG_RESTORE); |
568 | ftrace_start(); | ||
560 | resume_console(); | 569 | resume_console(); |
561 | 570 | ||
562 | Close: | 571 | Close: |
@@ -574,6 +583,10 @@ int hibernation_platform_enter(void) | |||
574 | */ | 583 | */ |
575 | static void power_down(void) | 584 | static void power_down(void) |
576 | { | 585 | { |
586 | #ifdef CONFIG_SUSPEND | ||
587 | int error; | ||
588 | #endif | ||
589 | |||
577 | switch (hibernation_mode) { | 590 | switch (hibernation_mode) { |
578 | case HIBERNATION_REBOOT: | 591 | case HIBERNATION_REBOOT: |
579 | kernel_restart(NULL); | 592 | kernel_restart(NULL); |
@@ -583,6 +596,25 @@ static void power_down(void) | |||
583 | case HIBERNATION_SHUTDOWN: | 596 | case HIBERNATION_SHUTDOWN: |
584 | kernel_power_off(); | 597 | kernel_power_off(); |
585 | break; | 598 | break; |
599 | #ifdef CONFIG_SUSPEND | ||
600 | case HIBERNATION_SUSPEND: | ||
601 | error = suspend_devices_and_enter(PM_SUSPEND_MEM); | ||
602 | if (error) { | ||
603 | if (hibernation_ops) | ||
604 | hibernation_mode = HIBERNATION_PLATFORM; | ||
605 | else | ||
606 | hibernation_mode = HIBERNATION_SHUTDOWN; | ||
607 | power_down(); | ||
608 | } | ||
609 | /* | ||
610 | * Restore swap signature. | ||
611 | */ | ||
612 | error = swsusp_unmark(); | ||
613 | if (error) | ||
614 | printk(KERN_ERR "PM: Swap will be unusable! " | ||
615 | "Try swapon -a.\n"); | ||
616 | return; | ||
617 | #endif | ||
586 | } | 618 | } |
587 | kernel_halt(); | 619 | kernel_halt(); |
588 | /* | 620 | /* |
@@ -748,13 +780,6 @@ static int software_resume(void) | |||
748 | async_synchronize_full(); | 780 | async_synchronize_full(); |
749 | } | 781 | } |
750 | 782 | ||
751 | /* | ||
752 | * We can't depend on SCSI devices being available after loading | ||
753 | * one of their modules until scsi_complete_async_scans() is | ||
754 | * called and the resume device usually is a SCSI one. | ||
755 | */ | ||
756 | scsi_complete_async_scans(); | ||
757 | |||
758 | swsusp_resume_device = name_to_dev_t(resume_file); | 783 | swsusp_resume_device = name_to_dev_t(resume_file); |
759 | if (!swsusp_resume_device) { | 784 | if (!swsusp_resume_device) { |
760 | error = -ENODEV; | 785 | error = -ENODEV; |
@@ -827,6 +852,9 @@ static const char * const hibernation_modes[] = { | |||
827 | [HIBERNATION_PLATFORM] = "platform", | 852 | [HIBERNATION_PLATFORM] = "platform", |
828 | [HIBERNATION_SHUTDOWN] = "shutdown", | 853 | [HIBERNATION_SHUTDOWN] = "shutdown", |
829 | [HIBERNATION_REBOOT] = "reboot", | 854 | [HIBERNATION_REBOOT] = "reboot", |
855 | #ifdef CONFIG_SUSPEND | ||
856 | [HIBERNATION_SUSPEND] = "suspend", | ||
857 | #endif | ||
830 | }; | 858 | }; |
831 | 859 | ||
832 | /* | 860 | /* |
@@ -867,6 +895,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, | |||
867 | switch (i) { | 895 | switch (i) { |
868 | case HIBERNATION_SHUTDOWN: | 896 | case HIBERNATION_SHUTDOWN: |
869 | case HIBERNATION_REBOOT: | 897 | case HIBERNATION_REBOOT: |
898 | #ifdef CONFIG_SUSPEND | ||
899 | case HIBERNATION_SUSPEND: | ||
900 | #endif | ||
870 | break; | 901 | break; |
871 | case HIBERNATION_PLATFORM: | 902 | case HIBERNATION_PLATFORM: |
872 | if (hibernation_ops) | 903 | if (hibernation_ops) |
@@ -907,6 +938,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
907 | switch (mode) { | 938 | switch (mode) { |
908 | case HIBERNATION_SHUTDOWN: | 939 | case HIBERNATION_SHUTDOWN: |
909 | case HIBERNATION_REBOOT: | 940 | case HIBERNATION_REBOOT: |
941 | #ifdef CONFIG_SUSPEND | ||
942 | case HIBERNATION_SUSPEND: | ||
943 | #endif | ||
910 | hibernation_mode = mode; | 944 | hibernation_mode = mode; |
911 | break; | 945 | break; |
912 | case HIBERNATION_PLATFORM: | 946 | case HIBERNATION_PLATFORM: |