aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
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);