|
@@ -52,6 +52,7 @@ enum {
|
|
#ifdef CONFIG_SUSPEND
|
|
#ifdef CONFIG_SUSPEND
|
|
HIBERNATION_SUSPEND,
|
|
HIBERNATION_SUSPEND,
|
|
#endif
|
|
#endif
|
|
|
|
+ HIBERNATION_TEST_RESUME,
|
|
/* keep last */
|
|
/* keep last */
|
|
__HIBERNATION_AFTER_LAST
|
|
__HIBERNATION_AFTER_LAST
|
|
};
|
|
};
|
|
@@ -647,12 +648,39 @@ static void power_down(void)
|
|
cpu_relax();
|
|
cpu_relax();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int load_image_and_restore(void)
|
|
|
|
+{
|
|
|
|
+ int error;
|
|
|
|
+ unsigned int flags;
|
|
|
|
+
|
|
|
|
+ pr_debug("PM: Loading hibernation image.\n");
|
|
|
|
+
|
|
|
|
+ lock_device_hotplug();
|
|
|
|
+ error = create_basic_memory_bitmaps();
|
|
|
|
+ if (error)
|
|
|
|
+ goto Unlock;
|
|
|
|
+
|
|
|
|
+ error = swsusp_read(&flags);
|
|
|
|
+ swsusp_close(FMODE_READ);
|
|
|
|
+ if (!error)
|
|
|
|
+ hibernation_restore(flags & SF_PLATFORM_MODE);
|
|
|
|
+
|
|
|
|
+ printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n");
|
|
|
|
+ swsusp_free();
|
|
|
|
+ free_basic_memory_bitmaps();
|
|
|
|
+ Unlock:
|
|
|
|
+ unlock_device_hotplug();
|
|
|
|
+
|
|
|
|
+ return error;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* hibernate - Carry out system hibernation, including saving the image.
|
|
* hibernate - Carry out system hibernation, including saving the image.
|
|
*/
|
|
*/
|
|
int hibernate(void)
|
|
int hibernate(void)
|
|
{
|
|
{
|
|
int error, nr_calls = 0;
|
|
int error, nr_calls = 0;
|
|
|
|
+ bool snapshot_test = false;
|
|
|
|
|
|
if (!hibernation_available()) {
|
|
if (!hibernation_available()) {
|
|
pr_debug("PM: Hibernation not available.\n");
|
|
pr_debug("PM: Hibernation not available.\n");
|
|
@@ -704,8 +732,12 @@ int hibernate(void)
|
|
pr_debug("PM: writing image.\n");
|
|
pr_debug("PM: writing image.\n");
|
|
error = swsusp_write(flags);
|
|
error = swsusp_write(flags);
|
|
swsusp_free();
|
|
swsusp_free();
|
|
- if (!error)
|
|
|
|
- power_down();
|
|
|
|
|
|
+ if (!error) {
|
|
|
|
+ if (hibernation_mode == HIBERNATION_TEST_RESUME)
|
|
|
|
+ snapshot_test = true;
|
|
|
|
+ else
|
|
|
|
+ power_down();
|
|
|
|
+ }
|
|
in_suspend = 0;
|
|
in_suspend = 0;
|
|
pm_restore_gfp_mask();
|
|
pm_restore_gfp_mask();
|
|
} else {
|
|
} else {
|
|
@@ -716,6 +748,12 @@ int hibernate(void)
|
|
free_basic_memory_bitmaps();
|
|
free_basic_memory_bitmaps();
|
|
Thaw:
|
|
Thaw:
|
|
unlock_device_hotplug();
|
|
unlock_device_hotplug();
|
|
|
|
+ if (snapshot_test) {
|
|
|
|
+ pr_debug("PM: Checking hibernation image\n");
|
|
|
|
+ error = swsusp_check();
|
|
|
|
+ if (!error)
|
|
|
|
+ error = load_image_and_restore();
|
|
|
|
+ }
|
|
thaw_processes();
|
|
thaw_processes();
|
|
|
|
|
|
/* Don't bother checking whether freezer_test_done is true */
|
|
/* Don't bother checking whether freezer_test_done is true */
|
|
@@ -748,7 +786,6 @@ int hibernate(void)
|
|
static int software_resume(void)
|
|
static int software_resume(void)
|
|
{
|
|
{
|
|
int error, nr_calls = 0;
|
|
int error, nr_calls = 0;
|
|
- unsigned int flags;
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* If the user said "noresume".. bail out early.
|
|
* If the user said "noresume".. bail out early.
|
|
@@ -844,24 +881,7 @@ static int software_resume(void)
|
|
error = freeze_processes();
|
|
error = freeze_processes();
|
|
if (error)
|
|
if (error)
|
|
goto Close_Finish;
|
|
goto Close_Finish;
|
|
-
|
|
|
|
- pr_debug("PM: Loading hibernation image.\n");
|
|
|
|
-
|
|
|
|
- lock_device_hotplug();
|
|
|
|
- error = create_basic_memory_bitmaps();
|
|
|
|
- if (error)
|
|
|
|
- goto Thaw;
|
|
|
|
-
|
|
|
|
- error = swsusp_read(&flags);
|
|
|
|
- swsusp_close(FMODE_READ);
|
|
|
|
- if (!error)
|
|
|
|
- hibernation_restore(flags & SF_PLATFORM_MODE);
|
|
|
|
-
|
|
|
|
- printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n");
|
|
|
|
- swsusp_free();
|
|
|
|
- free_basic_memory_bitmaps();
|
|
|
|
- Thaw:
|
|
|
|
- unlock_device_hotplug();
|
|
|
|
|
|
+ error = load_image_and_restore();
|
|
thaw_processes();
|
|
thaw_processes();
|
|
Finish:
|
|
Finish:
|
|
__pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
|
|
__pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
|
|
@@ -887,6 +907,7 @@ static const char * const hibernation_modes[] = {
|
|
#ifdef CONFIG_SUSPEND
|
|
#ifdef CONFIG_SUSPEND
|
|
[HIBERNATION_SUSPEND] = "suspend",
|
|
[HIBERNATION_SUSPEND] = "suspend",
|
|
#endif
|
|
#endif
|
|
|
|
+ [HIBERNATION_TEST_RESUME] = "test_resume",
|
|
};
|
|
};
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -933,6 +954,7 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
|
|
#ifdef CONFIG_SUSPEND
|
|
#ifdef CONFIG_SUSPEND
|
|
case HIBERNATION_SUSPEND:
|
|
case HIBERNATION_SUSPEND:
|
|
#endif
|
|
#endif
|
|
|
|
+ case HIBERNATION_TEST_RESUME:
|
|
break;
|
|
break;
|
|
case HIBERNATION_PLATFORM:
|
|
case HIBERNATION_PLATFORM:
|
|
if (hibernation_ops)
|
|
if (hibernation_ops)
|
|
@@ -979,6 +1001,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
|
|
#ifdef CONFIG_SUSPEND
|
|
#ifdef CONFIG_SUSPEND
|
|
case HIBERNATION_SUSPEND:
|
|
case HIBERNATION_SUSPEND:
|
|
#endif
|
|
#endif
|
|
|
|
+ case HIBERNATION_TEST_RESUME:
|
|
hibernation_mode = mode;
|
|
hibernation_mode = mode;
|
|
break;
|
|
break;
|
|
case HIBERNATION_PLATFORM:
|
|
case HIBERNATION_PLATFORM:
|