: In kernel hibernation, suspend to both: draft
Subsystems (2)
PATCH 1/1 : In kernel hibernation, suspend to both: draft
Hi Rafael,
Was just playing with it and this is what I came up with. This is just a rough draft (I didn't even think of memory leaks and such here, to be honest). Let me know what you think.
------------------------------
Documentation/power/swsusp.txt +5 -0
@@ -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
kernel/power/hibernate.c +36 -0
@@ -5,6 +5,7 @@* Copyright (c) 2003 Open Source Development Lab * Copyright (c) 2004 Pavel Machek <[email protected]> * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc. +* Copyright (C) 2012 Bojan Smojver <[email protected]> * * This file is released under the GPLv2. */
@@ -44,6 +45,9 @@ enum {HIBERNATION_PLATFORM ,HIBERNATION_SHUTDOWN ,HIBERNATION_REBOOT , +#ifdef CONFIG_SUSPEND +HIBERNATION_SUSPEND , +#endif/* keep last */ __HIBERNATION_AFTER_LAST };
@@ -572,6 +576,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 );
@@ -581,6 +589,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 ();/*
@@ -814,6 +841,9 @@ static const char * const hibernation_modes[] = { [HIBERNATION_PLATFORM] = "platform", [HIBERNATION_SHUTDOWN] = "shutdown", [HIBERNATION_REBOOT ] ="reboot" , +#ifdef CONFIG_SUSPEND + [HIBERNATION_SUSPEND] = "suspend", +#endif };/*
@@ -854,6 +884,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)
@@ -894,6 +927,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 :
kernel/power/power.h +3 -0
@@ -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;
kernel/power/swap.c +28 -0
@@ -1456,6 +1456,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 );
------------------------------
Signature · 1 line
Bojan
Hi,
Quoted 5 lines · Bojan Smojver
Hi Rafael,
Was just playing with it and this is what I came up with. This is just a rough draft (I didn't even think of memory leaks and such here, to be honest). Let me know what you think.
Looks reasonable at first sight.
Thanks,
Rafael
Quoted 162 lines
------------------------------
Documentation/power/swsusp.txt +5
-0@@ -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 makekernel/power/hibernate.c +36
-0@@ -5,6 +5,7 @@* Copyright (c) 2003 Open Source Development Lab * Copyright (c) 2004 Pavel Machek <[email protected]> * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc. +* Copyright (C) 2012 Bojan Smojver <[email protected]> * * This file is released under the GPLv2. */ @@ -44,6 +45,9 @@ enum {HIBERNATION_PLATFORM ,HIBERNATION_SHUTDOWN ,HIBERNATION_REBOOT , +#ifdef CONFIG_SUSPEND +HIBERNATION_SUSPEND , +#endif/* keep last */ __HIBERNATION_AFTER_LAST };@@ -572,6 +576,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 );@@ -581,6 +589,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 ();/* @@ -814,6 +841,9 @@ static const char * const hibernation_modes[] = { [HIBERNATION_PLATFORM] = "platform", [HIBERNATION_SHUTDOWN] = "shutdown", [HIBERNATION_REBOOT ] ="reboot" , +#ifdef CONFIG_SUSPEND + [HIBERNATION_SUSPEND] = "suspend", +#endif };/* @@ -854,6 +884,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)@@ -894,6 +927,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 :kernel/power/power.h +3
-0@@ -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;kernel/power/swap.c +28
-1@@ -1456,6 +1456,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 ); ------------------------------
Quoted 1 line · Rafael J. Wysocki
Looks reasonable at first sight.
OK, thanks for having a look! I'll check to see whether memory for hibernation is been released properly and then I may submit this for real. BTW, the patch actually worked on my ThinkPad T510. The miracles never stop. :-)
Just to be sure - I should prepare a patch against your linux-next branch, correct? This patch was against mainline, which is still somewhat behind.
Signature · 1 line
Bojan
Quoted 10 lines · Bojan Smojver
Quoted 1 line · Rafael J. Wysocki
Looks reasonable at first sight.
OK, thanks for having a look! I'll check to see whether memory for hibernation is been released properly and then I may submit this for real. BTW, the patch actually worked on my ThinkPad T510. The miracles never stop. :-)
Just to be sure - I should prepare a patch against your linux-next branch, correct?
Yup.
Quoted 9 lines · Rafael J. Wysocki
Quoted 8 lines · Bojan Smojver
Quoted 1 line · Rafael J. Wysocki
Looks reasonable at first sight.
OK, thanks for having a look! I'll check to see whether memory for hibernation is been released properly and then I may submit this for real. BTW, the patch actually worked on my ThinkPad T510. The miracles never stop. :-)
Quoted 4 lines
Quoted 2 lines
Just to be sure - I should prepare a patch against your linux-next branch, correct?
Yup.
Oh goody, that's what the apples do - suspend to ram and disk. When you have the patch ready, you'll have another tester, just send it on my way too pls :-).
Thanks.
Signature · 2 lines
Regards/Gruss,
Boris.Quoted 3 lines · Borislav Petkov
Oh goody, that's what the apples do - suspend to ram and disk. When you have the patch ready, you'll have another tester, just send it on my way too pls :-).
Pretty much the same thing submitted to Rafael here:
http://marc.info/?l=linux-kernel&m=133651588229850&w=2
It worked on my ThinkPad, but YMMV. :-)
Signature · 1 line
Bojan