aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorBojan Smojver <bojan@rexursive.com>2012-06-15 18:09:58 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-07-01 07:31:22 -0400
commit62c552ccc3eda1198632a4f344aa32623d226bab (patch)
treefbd85e76542a715a8e988dddb59e3df859939fb5 /kernel
parent6887a4131da3adaab011613776d865f4bcfb5678 (diff)
PM / Hibernate: Enable suspend to both for in-kernel hibernation.
It is often useful to suspend to memory after hibernation image has been written to disk. If the battery runs out or power is otherwise lost, the computer will resume from the hibernated image. If not, it will resume from memory and hibernation image will be discarded. Signed-off-by: Bojan Smojver <bojan@rexursive.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/hibernate.c36
-rw-r--r--kernel/power/power.h3
-rw-r--r--kernel/power/swap.c28
3 files changed, 67 insertions, 0 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 8b53db38a279..21ad3fe3164f 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 */
@@ -46,6 +47,9 @@ enum {
46 HIBERNATION_PLATFORM, 47 HIBERNATION_PLATFORM,
47 HIBERNATION_SHUTDOWN, 48 HIBERNATION_SHUTDOWN,
48 HIBERNATION_REBOOT, 49 HIBERNATION_REBOOT,
50#ifdef CONFIG_SUSPEND
51 HIBERNATION_SUSPEND,
52#endif
49 /* keep last */ 53 /* keep last */
50 __HIBERNATION_AFTER_LAST 54 __HIBERNATION_AFTER_LAST
51}; 55};
@@ -574,6 +578,10 @@ int hibernation_platform_enter(void)
574 */ 578 */
575static void power_down(void) 579static void power_down(void)
576{ 580{
581#ifdef CONFIG_SUSPEND
582 int error;
583#endif
584
577 switch (hibernation_mode) { 585 switch (hibernation_mode) {
578 case HIBERNATION_REBOOT: 586 case HIBERNATION_REBOOT:
579 kernel_restart(NULL); 587 kernel_restart(NULL);
@@ -583,6 +591,25 @@ static void power_down(void)
583 case HIBERNATION_SHUTDOWN: 591 case HIBERNATION_SHUTDOWN:
584 kernel_power_off(); 592 kernel_power_off();
585 break; 593 break;
594#ifdef CONFIG_SUSPEND
595 case HIBERNATION_SUSPEND:
596 error = suspend_devices_and_enter(PM_SUSPEND_MEM);
597 if (error) {
598 if (hibernation_ops)
599 hibernation_mode = HIBERNATION_PLATFORM;
600 else
601 hibernation_mode = HIBERNATION_SHUTDOWN;
602 power_down();
603 }
604 /*
605 * Restore swap signature.
606 */
607 error = swsusp_unmark();
608 if (error)
609 printk(KERN_ERR "PM: Swap will be unusable! "
610 "Try swapon -a.\n");
611 return;
612#endif
586 } 613 }
587 kernel_halt(); 614 kernel_halt();
588 /* 615 /*
@@ -827,6 +854,9 @@ static const char * const hibernation_modes[] = {
827 [HIBERNATION_PLATFORM] = "platform", 854 [HIBERNATION_PLATFORM] = "platform",
828 [HIBERNATION_SHUTDOWN] = "shutdown", 855 [HIBERNATION_SHUTDOWN] = "shutdown",
829 [HIBERNATION_REBOOT] = "reboot", 856 [HIBERNATION_REBOOT] = "reboot",
857#ifdef CONFIG_SUSPEND
858 [HIBERNATION_SUSPEND] = "suspend",
859#endif
830}; 860};
831 861
832/* 862/*
@@ -867,6 +897,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
867 switch (i) { 897 switch (i) {
868 case HIBERNATION_SHUTDOWN: 898 case HIBERNATION_SHUTDOWN:
869 case HIBERNATION_REBOOT: 899 case HIBERNATION_REBOOT:
900#ifdef CONFIG_SUSPEND
901 case HIBERNATION_SUSPEND:
902#endif
870 break; 903 break;
871 case HIBERNATION_PLATFORM: 904 case HIBERNATION_PLATFORM:
872 if (hibernation_ops) 905 if (hibernation_ops)
@@ -907,6 +940,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
907 switch (mode) { 940 switch (mode) {
908 case HIBERNATION_SHUTDOWN: 941 case HIBERNATION_SHUTDOWN:
909 case HIBERNATION_REBOOT: 942 case HIBERNATION_REBOOT:
943#ifdef CONFIG_SUSPEND
944 case HIBERNATION_SUSPEND:
945#endif
910 hibernation_mode = mode; 946 hibernation_mode = mode;
911 break; 947 break;
912 case HIBERNATION_PLATFORM: 948 case HIBERNATION_PLATFORM:
diff --git a/kernel/power/power.h b/kernel/power/power.h
index b0bd4beaebfe..7d4b7ffb3c1d 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -156,6 +156,9 @@ extern void swsusp_free(void);
156extern int swsusp_read(unsigned int *flags_p); 156extern int swsusp_read(unsigned int *flags_p);
157extern int swsusp_write(unsigned int flags); 157extern int swsusp_write(unsigned int flags);
158extern void swsusp_close(fmode_t); 158extern void swsusp_close(fmode_t);
159#ifdef CONFIG_SUSPEND
160extern int swsusp_unmark(void);
161#endif
159 162
160/* kernel/power/block_io.c */ 163/* kernel/power/block_io.c */
161extern struct block_device *hib_resume_bdev; 164extern struct block_device *hib_resume_bdev;
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 11e22c068e8b..83d505142b00 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -1472,6 +1472,34 @@ void swsusp_close(fmode_t mode)
1472 blkdev_put(hib_resume_bdev, mode); 1472 blkdev_put(hib_resume_bdev, mode);
1473} 1473}
1474 1474
1475/**
1476 * swsusp_unmark - Unmark swsusp signature in the resume device
1477 */
1478
1479#ifdef CONFIG_SUSPEND
1480int swsusp_unmark(void)
1481{
1482 int error;
1483
1484 hib_bio_read_page(swsusp_resume_block, swsusp_header, NULL);
1485 if (!memcmp(HIBERNATE_SIG,swsusp_header->sig, 10)) {
1486 memcpy(swsusp_header->sig,swsusp_header->orig_sig, 10);
1487 error = hib_bio_write_page(swsusp_resume_block,
1488 swsusp_header, NULL);
1489 } else {
1490 printk(KERN_ERR "PM: Cannot find swsusp signature!\n");
1491 error = -ENODEV;
1492 }
1493
1494 /*
1495 * We just returned from suspend, we don't need the image any more.
1496 */
1497 free_all_swap_pages(root_swap);
1498
1499 return error;
1500}
1501#endif
1502
1475static int swsusp_header_init(void) 1503static int swsusp_header_init(void)
1476{ 1504{
1477 swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL); 1505 swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);