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: |
