Skip to content

Commit

Permalink
PM / Hibernate: Enable suspend to both for in-kernel hibernation.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Bojan Smojver authored and Rafael J. Wysocki committed Jul 1, 2012
1 parent 6887a41 commit 62c552c
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 0 deletions.
5 changes: 5 additions & 0 deletions Documentation/power/swsusp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ echo shutdown > /sys/power/disk; echo disk > /sys/power/state

echo platform > /sys/power/disk; echo disk > /sys/power/state

. If you would like to write hibernation image to swap and then suspend
to RAM (provided your platform supports it), you can try

echo suspend > /sys/power/disk; echo disk > /sys/power/state

. If you have SATA disks, you'll need recent kernels with SATA suspend
support. For suspend and resume to work, make sure your disk drivers
are built into kernel -- not modules. [There's way to make
Expand Down
36 changes: 36 additions & 0 deletions kernel/power/hibernate.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Copyright (c) 2003 Open Source Development Lab
* Copyright (c) 2004 Pavel Machek <pavel@ucw.cz>
* Copyright (c) 2009 Rafael J. Wysocki, Novell Inc.
* Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com>
*
* This file is released under the GPLv2.
*/
Expand Down Expand Up @@ -46,6 +47,9 @@ enum {
HIBERNATION_PLATFORM,
HIBERNATION_SHUTDOWN,
HIBERNATION_REBOOT,
#ifdef CONFIG_SUSPEND
HIBERNATION_SUSPEND,
#endif
/* keep last */
__HIBERNATION_AFTER_LAST
};
Expand Down Expand Up @@ -574,6 +578,10 @@ int hibernation_platform_enter(void)
*/
static void power_down(void)
{
#ifdef CONFIG_SUSPEND
int error;
#endif

switch (hibernation_mode) {
case HIBERNATION_REBOOT:
kernel_restart(NULL);
Expand All @@ -583,6 +591,25 @@ static void power_down(void)
case HIBERNATION_SHUTDOWN:
kernel_power_off();
break;
#ifdef CONFIG_SUSPEND
case HIBERNATION_SUSPEND:
error = suspend_devices_and_enter(PM_SUSPEND_MEM);
if (error) {
if (hibernation_ops)
hibernation_mode = HIBERNATION_PLATFORM;
else
hibernation_mode = HIBERNATION_SHUTDOWN;
power_down();
}
/*
* Restore swap signature.
*/
error = swsusp_unmark();
if (error)
printk(KERN_ERR "PM: Swap will be unusable! "
"Try swapon -a.\n");
return;
#endif
}
kernel_halt();
/*
Expand Down Expand Up @@ -827,6 +854,9 @@ static const char * const hibernation_modes[] = {
[HIBERNATION_PLATFORM] = "platform",
[HIBERNATION_SHUTDOWN] = "shutdown",
[HIBERNATION_REBOOT] = "reboot",
#ifdef CONFIG_SUSPEND
[HIBERNATION_SUSPEND] = "suspend",
#endif
};

/*
Expand Down Expand Up @@ -867,6 +897,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
switch (i) {
case HIBERNATION_SHUTDOWN:
case HIBERNATION_REBOOT:
#ifdef CONFIG_SUSPEND
case HIBERNATION_SUSPEND:
#endif
break;
case HIBERNATION_PLATFORM:
if (hibernation_ops)
Expand Down Expand Up @@ -907,6 +940,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
switch (mode) {
case HIBERNATION_SHUTDOWN:
case HIBERNATION_REBOOT:
#ifdef CONFIG_SUSPEND
case HIBERNATION_SUSPEND:
#endif
hibernation_mode = mode;
break;
case HIBERNATION_PLATFORM:
Expand Down
3 changes: 3 additions & 0 deletions kernel/power/power.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ extern void swsusp_free(void);
extern int swsusp_read(unsigned int *flags_p);
extern int swsusp_write(unsigned int flags);
extern void swsusp_close(fmode_t);
#ifdef CONFIG_SUSPEND
extern int swsusp_unmark(void);
#endif

/* kernel/power/block_io.c */
extern struct block_device *hib_resume_bdev;
Expand Down
28 changes: 28 additions & 0 deletions kernel/power/swap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1472,6 +1472,34 @@ void swsusp_close(fmode_t mode)
blkdev_put(hib_resume_bdev, mode);
}

/**
* swsusp_unmark - Unmark swsusp signature in the resume device
*/

#ifdef CONFIG_SUSPEND
int swsusp_unmark(void)
{
int error;

hib_bio_read_page(swsusp_resume_block, swsusp_header, NULL);
if (!memcmp(HIBERNATE_SIG,swsusp_header->sig, 10)) {
memcpy(swsusp_header->sig,swsusp_header->orig_sig, 10);
error = hib_bio_write_page(swsusp_resume_block,
swsusp_header, NULL);
} else {
printk(KERN_ERR "PM: Cannot find swsusp signature!\n");
error = -ENODEV;
}

/*
* We just returned from suspend, we don't need the image any more.
*/
free_all_swap_pages(root_swap);

return error;
}
#endif

static int swsusp_header_init(void)
{
swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);
Expand Down

0 comments on commit 62c552c

Please sign in to comment.