swsusp: remove code duplication between disk.c and user.c
Currently, much of the code in kernel/power/disk.c is duplicated in kernel/power/user.c , mainly for historical reasons. By eliminating this code duplication we can reduce the size of user.c quite substantially and remove the maintenance difficulty resulting from it. [bunk@stusta.de: kernel/power/disk.c: make code static] Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Cc: Nigel Cunningham <nigel@nigel.suspend2.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
127067a9c9
commit
7777fab989
@ -45,7 +45,7 @@ enum {
|
|||||||
|
|
||||||
static int hibernation_mode = HIBERNATION_SHUTDOWN;
|
static int hibernation_mode = HIBERNATION_SHUTDOWN;
|
||||||
|
|
||||||
struct hibernation_ops *hibernation_ops;
|
static struct hibernation_ops *hibernation_ops;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hibernation_set_ops - set the global hibernate operations
|
* hibernation_set_ops - set the global hibernate operations
|
||||||
@ -74,9 +74,9 @@ void hibernation_set_ops(struct hibernation_ops *ops)
|
|||||||
* platform driver if so configured and return an error code if it fails
|
* platform driver if so configured and return an error code if it fails
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int platform_prepare(void)
|
static int platform_prepare(int platform_mode)
|
||||||
{
|
{
|
||||||
return (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) ?
|
return (platform_mode && hibernation_ops) ?
|
||||||
hibernation_ops->prepare() : 0;
|
hibernation_ops->prepare() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,12 +85,103 @@ static int platform_prepare(void)
|
|||||||
* using the platform driver (must be called after platform_prepare())
|
* using the platform driver (must be called after platform_prepare())
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void platform_finish(void)
|
static void platform_finish(int platform_mode)
|
||||||
{
|
{
|
||||||
if (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops)
|
if (platform_mode && hibernation_ops)
|
||||||
hibernation_ops->finish();
|
hibernation_ops->finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hibernation_snapshot - quiesce devices and create the hibernation
|
||||||
|
* snapshot image.
|
||||||
|
* @platform_mode - if set, use the platform driver, if available, to
|
||||||
|
* prepare the platform frimware for the power transition.
|
||||||
|
*
|
||||||
|
* Must be called with pm_mutex held
|
||||||
|
*/
|
||||||
|
|
||||||
|
int hibernation_snapshot(int platform_mode)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Free memory before shutting down devices. */
|
||||||
|
error = swsusp_shrink_memory();
|
||||||
|
if (error)
|
||||||
|
goto Finish;
|
||||||
|
|
||||||
|
error = platform_prepare(platform_mode);
|
||||||
|
if (error)
|
||||||
|
goto Finish;
|
||||||
|
|
||||||
|
suspend_console();
|
||||||
|
error = device_suspend(PMSG_FREEZE);
|
||||||
|
if (error)
|
||||||
|
goto Resume_devices;
|
||||||
|
|
||||||
|
error = disable_nonboot_cpus();
|
||||||
|
if (!error) {
|
||||||
|
if (hibernation_mode != HIBERNATION_TEST) {
|
||||||
|
in_suspend = 1;
|
||||||
|
error = swsusp_suspend();
|
||||||
|
/* Control returns here after successful restore */
|
||||||
|
} else {
|
||||||
|
printk("swsusp debug: Waiting for 5 seconds.\n");
|
||||||
|
mdelay(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enable_nonboot_cpus();
|
||||||
|
Resume_devices:
|
||||||
|
platform_finish(platform_mode);
|
||||||
|
device_resume();
|
||||||
|
resume_console();
|
||||||
|
Finish:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hibernation_restore - quiesce devices and restore the hibernation
|
||||||
|
* snapshot image. If successful, control returns in hibernation_snaphot()
|
||||||
|
*
|
||||||
|
* Must be called with pm_mutex held
|
||||||
|
*/
|
||||||
|
|
||||||
|
int hibernation_restore(void)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
pm_prepare_console();
|
||||||
|
suspend_console();
|
||||||
|
error = device_suspend(PMSG_PRETHAW);
|
||||||
|
if (error)
|
||||||
|
goto Finish;
|
||||||
|
|
||||||
|
error = disable_nonboot_cpus();
|
||||||
|
if (!error)
|
||||||
|
error = swsusp_resume();
|
||||||
|
|
||||||
|
enable_nonboot_cpus();
|
||||||
|
Finish:
|
||||||
|
device_resume();
|
||||||
|
resume_console();
|
||||||
|
pm_restore_console();
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hibernation_platform_enter - enter the hibernation state using the
|
||||||
|
* platform driver (if available)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int hibernation_platform_enter(void)
|
||||||
|
{
|
||||||
|
if (hibernation_ops) {
|
||||||
|
kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
|
||||||
|
return hibernation_ops->enter();
|
||||||
|
} else {
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* power_down - Shut the machine down for hibernation.
|
* power_down - Shut the machine down for hibernation.
|
||||||
*
|
*
|
||||||
@ -111,11 +202,7 @@ static void power_down(void)
|
|||||||
kernel_restart(NULL);
|
kernel_restart(NULL);
|
||||||
break;
|
break;
|
||||||
case HIBERNATION_PLATFORM:
|
case HIBERNATION_PLATFORM:
|
||||||
if (hibernation_ops) {
|
hibernation_platform_enter();
|
||||||
kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
|
|
||||||
hibernation_ops->enter();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
kernel_halt();
|
kernel_halt();
|
||||||
/*
|
/*
|
||||||
@ -171,62 +258,17 @@ int hibernate(void)
|
|||||||
mdelay(5000);
|
mdelay(5000);
|
||||||
goto Thaw;
|
goto Thaw;
|
||||||
}
|
}
|
||||||
|
error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
|
||||||
/* Free memory before shutting down devices. */
|
if (in_suspend && !error) {
|
||||||
error = swsusp_shrink_memory();
|
|
||||||
if (error)
|
|
||||||
goto Thaw;
|
|
||||||
|
|
||||||
error = platform_prepare();
|
|
||||||
if (error)
|
|
||||||
goto Thaw;
|
|
||||||
|
|
||||||
suspend_console();
|
|
||||||
error = device_suspend(PMSG_FREEZE);
|
|
||||||
if (error) {
|
|
||||||
printk(KERN_ERR "PM: Some devices failed to suspend\n");
|
|
||||||
goto Resume_devices;
|
|
||||||
}
|
|
||||||
error = disable_nonboot_cpus();
|
|
||||||
if (error)
|
|
||||||
goto Enable_cpus;
|
|
||||||
|
|
||||||
if (hibernation_mode == HIBERNATION_TEST) {
|
|
||||||
printk("swsusp debug: Waiting for 5 seconds.\n");
|
|
||||||
mdelay(5000);
|
|
||||||
goto Enable_cpus;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_debug("PM: snapshotting memory.\n");
|
|
||||||
in_suspend = 1;
|
|
||||||
error = swsusp_suspend();
|
|
||||||
if (error)
|
|
||||||
goto Enable_cpus;
|
|
||||||
|
|
||||||
if (in_suspend) {
|
|
||||||
enable_nonboot_cpus();
|
|
||||||
platform_finish();
|
|
||||||
device_resume();
|
|
||||||
resume_console();
|
|
||||||
pr_debug("PM: writing image.\n");
|
pr_debug("PM: writing image.\n");
|
||||||
error = swsusp_write();
|
error = swsusp_write();
|
||||||
|
swsusp_free();
|
||||||
if (!error)
|
if (!error)
|
||||||
power_down();
|
power_down();
|
||||||
else {
|
|
||||||
swsusp_free();
|
|
||||||
goto Thaw;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
pr_debug("PM: Image restored successfully.\n");
|
pr_debug("PM: Image restored successfully.\n");
|
||||||
|
swsusp_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
swsusp_free();
|
|
||||||
Enable_cpus:
|
|
||||||
enable_nonboot_cpus();
|
|
||||||
Resume_devices:
|
|
||||||
platform_finish();
|
|
||||||
device_resume();
|
|
||||||
resume_console();
|
|
||||||
Thaw:
|
Thaw:
|
||||||
mutex_unlock(&pm_mutex);
|
mutex_unlock(&pm_mutex);
|
||||||
unprepare_processes();
|
unprepare_processes();
|
||||||
@ -301,29 +343,11 @@ static int software_resume(void)
|
|||||||
pr_debug("PM: Reading swsusp image.\n");
|
pr_debug("PM: Reading swsusp image.\n");
|
||||||
|
|
||||||
error = swsusp_read();
|
error = swsusp_read();
|
||||||
if (error) {
|
|
||||||
swsusp_free();
|
|
||||||
goto Thaw;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_debug("PM: Preparing devices for restore.\n");
|
|
||||||
|
|
||||||
suspend_console();
|
|
||||||
error = device_suspend(PMSG_PRETHAW);
|
|
||||||
if (error)
|
|
||||||
goto Free;
|
|
||||||
|
|
||||||
error = disable_nonboot_cpus();
|
|
||||||
if (!error)
|
if (!error)
|
||||||
swsusp_resume();
|
hibernation_restore();
|
||||||
|
|
||||||
enable_nonboot_cpus();
|
|
||||||
Free:
|
|
||||||
swsusp_free();
|
|
||||||
device_resume();
|
|
||||||
resume_console();
|
|
||||||
Thaw:
|
|
||||||
printk(KERN_ERR "PM: Restore failed, recovering.\n");
|
printk(KERN_ERR "PM: Restore failed, recovering.\n");
|
||||||
|
swsusp_free();
|
||||||
unprepare_processes();
|
unprepare_processes();
|
||||||
Done:
|
Done:
|
||||||
free_basic_memory_bitmaps();
|
free_basic_memory_bitmaps();
|
||||||
@ -333,7 +357,7 @@ static int software_resume(void)
|
|||||||
Unlock:
|
Unlock:
|
||||||
mutex_unlock(&pm_mutex);
|
mutex_unlock(&pm_mutex);
|
||||||
pr_debug("PM: Resume from disk failed.\n");
|
pr_debug("PM: Resume from disk failed.\n");
|
||||||
return 0;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
late_initcall(software_resume);
|
late_initcall(software_resume);
|
||||||
|
@ -25,7 +25,10 @@ struct swsusp_info {
|
|||||||
*/
|
*/
|
||||||
#define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT)
|
#define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT)
|
||||||
|
|
||||||
extern struct hibernation_ops *hibernation_ops;
|
/* kernel/power/disk.c */
|
||||||
|
extern int hibernation_snapshot(int platform_mode);
|
||||||
|
extern int hibernation_restore(void);
|
||||||
|
extern int hibernation_platform_enter(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int pfn_is_nosave(unsigned long);
|
extern int pfn_is_nosave(unsigned long);
|
||||||
|
@ -128,83 +128,6 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int platform_prepare(void)
|
|
||||||
{
|
|
||||||
int error = 0;
|
|
||||||
|
|
||||||
if (hibernation_ops)
|
|
||||||
error = hibernation_ops->prepare();
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void platform_finish(void)
|
|
||||||
{
|
|
||||||
if (hibernation_ops)
|
|
||||||
hibernation_ops->finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int snapshot_suspend(int platform_suspend)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
|
|
||||||
mutex_lock(&pm_mutex);
|
|
||||||
/* Free memory before shutting down devices. */
|
|
||||||
error = swsusp_shrink_memory();
|
|
||||||
if (error)
|
|
||||||
goto Finish;
|
|
||||||
|
|
||||||
if (platform_suspend) {
|
|
||||||
error = platform_prepare();
|
|
||||||
if (error)
|
|
||||||
goto Finish;
|
|
||||||
}
|
|
||||||
suspend_console();
|
|
||||||
error = device_suspend(PMSG_FREEZE);
|
|
||||||
if (error)
|
|
||||||
goto Resume_devices;
|
|
||||||
|
|
||||||
error = disable_nonboot_cpus();
|
|
||||||
if (!error) {
|
|
||||||
in_suspend = 1;
|
|
||||||
error = swsusp_suspend();
|
|
||||||
}
|
|
||||||
enable_nonboot_cpus();
|
|
||||||
Resume_devices:
|
|
||||||
if (platform_suspend)
|
|
||||||
platform_finish();
|
|
||||||
|
|
||||||
device_resume();
|
|
||||||
resume_console();
|
|
||||||
Finish:
|
|
||||||
mutex_unlock(&pm_mutex);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int snapshot_restore(void)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
|
|
||||||
mutex_lock(&pm_mutex);
|
|
||||||
pm_prepare_console();
|
|
||||||
suspend_console();
|
|
||||||
error = device_suspend(PMSG_PRETHAW);
|
|
||||||
if (error)
|
|
||||||
goto Finish;
|
|
||||||
|
|
||||||
error = disable_nonboot_cpus();
|
|
||||||
if (!error)
|
|
||||||
error = swsusp_resume();
|
|
||||||
|
|
||||||
enable_nonboot_cpus();
|
|
||||||
Finish:
|
|
||||||
device_resume();
|
|
||||||
resume_console();
|
|
||||||
pm_restore_console();
|
|
||||||
mutex_unlock(&pm_mutex);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snapshot_ioctl(struct inode *inode, struct file *filp,
|
static int snapshot_ioctl(struct inode *inode, struct file *filp,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
@ -251,7 +174,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
|
|||||||
error = -EPERM;
|
error = -EPERM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
error = snapshot_suspend(data->platform_suspend);
|
error = hibernation_snapshot(data->platform_suspend);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = put_user(in_suspend, (unsigned int __user *)arg);
|
error = put_user(in_suspend, (unsigned int __user *)arg);
|
||||||
if (!error)
|
if (!error)
|
||||||
@ -265,7 +188,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
|
|||||||
error = -EPERM;
|
error = -EPERM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
error = snapshot_restore();
|
error = hibernation_restore();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SNAPSHOT_FREE:
|
case SNAPSHOT_FREE:
|
||||||
@ -377,19 +300,14 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
|
|||||||
switch (arg) {
|
switch (arg) {
|
||||||
|
|
||||||
case PMOPS_PREPARE:
|
case PMOPS_PREPARE:
|
||||||
if (hibernation_ops) {
|
data->platform_suspend = 1;
|
||||||
data->platform_suspend = 1;
|
error = 0;
|
||||||
error = 0;
|
|
||||||
} else {
|
|
||||||
error = -ENOSYS;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PMOPS_ENTER:
|
case PMOPS_ENTER:
|
||||||
if (data->platform_suspend) {
|
if (data->platform_suspend)
|
||||||
kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
|
error = hibernation_platform_enter();
|
||||||
error = hibernation_ops->enter();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PMOPS_FINISH:
|
case PMOPS_FINISH:
|
||||||
|
Loading…
Reference in New Issue
Block a user