summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-power17
-rw-r--r--Documentation/power/interface.txt13
-rw-r--r--include/linux/pm.h4
-rw-r--r--kernel/power/disk.c37
4 files changed, 60 insertions, 11 deletions
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index d882f8093871..dcff4d0623ad 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -21,7 +21,7 @@ Description:
these states.
What: /sys/power/disk
-Date: August 2006
+Date: September 2006
Contact: Rafael J. Wysocki <rjw@sisk.pl>
Description:
The /sys/power/disk file controls the operating mode of the
@@ -39,6 +39,19 @@ Description:
'reboot' - the memory image will be saved by the kernel and
the system will be rebooted.
+ Additionally, /sys/power/disk can be used to turn on one of the
+ two testing modes of the suspend-to-disk mechanism: 'testproc'
+ or 'test'. If the suspend-to-disk mechanism is in the
+ 'testproc' mode, writing 'disk' to /sys/power/state will cause
+ the kernel to disable nonboot CPUs and freeze tasks, wait for 5
+ seconds, unfreeze tasks and enable nonboot CPUs. If it is in
+ the 'test' mode, writing 'disk' to /sys/power/state will cause
+ the kernel to disable nonboot CPUs and freeze tasks, shrink
+ memory, suspend devices, wait for 5 seconds, resume devices,
+ unfreeze tasks and enable nonboot CPUs. Then, we are able to
+ look in the log messages and work out, for example, which code
+ is being slow and which device drivers are misbehaving.
+
The suspend-to-disk method may be chosen by writing to this
file one of the accepted strings:
@@ -46,6 +59,8 @@ Description:
'platform'
'shutdown'
'reboot'
+ 'testproc'
+ 'test'
It will only change to 'firmware' or 'platform' if the system
supports that.
diff --git a/Documentation/power/interface.txt b/Documentation/power/interface.txt
index a66bec222b16..74311d7e0f3c 100644
--- a/Documentation/power/interface.txt
+++ b/Documentation/power/interface.txt
@@ -30,6 +30,17 @@ testing). The system will support either 'firmware' or 'platform', and
that is known a priori. But, the user may choose 'shutdown' or
'reboot' as alternatives.
+Additionally, /sys/power/disk can be used to turn on one of the two testing
+modes of the suspend-to-disk mechanism: 'testproc' or 'test'. If the
+suspend-to-disk mechanism is in the 'testproc' mode, writing 'disk' to
+/sys/power/state will cause the kernel to disable nonboot CPUs and freeze
+tasks, wait for 5 seconds, unfreeze tasks and enable nonboot CPUs. If it is
+in the 'test' mode, writing 'disk' to /sys/power/state will cause the kernel
+to disable nonboot CPUs and freeze tasks, shrink memory, suspend devices, wait
+for 5 seconds, resume devices, unfreeze tasks and enable nonboot CPUs. Then,
+we are able to look in the log messages and work out, for example, which code
+is being slow and which device drivers are misbehaving.
+
Reading from this file will display what the mode is currently set
to. Writing to this file will accept one of
@@ -37,6 +48,8 @@ to. Writing to this file will accept one of
'platform'
'shutdown'
'reboot'
+ 'testproc'
+ 'test'
It will only change to 'firmware' or 'platform' if the system supports
it.
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 6b27e07aef19..070394e846d0 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -116,7 +116,9 @@ typedef int __bitwise suspend_disk_method_t;
#define PM_DISK_PLATFORM ((__force suspend_disk_method_t) 2)
#define PM_DISK_SHUTDOWN ((__force suspend_disk_method_t) 3)
#define PM_DISK_REBOOT ((__force suspend_disk_method_t) 4)
-#define PM_DISK_MAX ((__force suspend_disk_method_t) 5)
+#define PM_DISK_TEST ((__force suspend_disk_method_t) 5)
+#define PM_DISK_TESTPROC ((__force suspend_disk_method_t) 6)
+#define PM_DISK_MAX ((__force suspend_disk_method_t) 7)
struct pm_ops {
suspend_disk_method_t pm_disk_mode;
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index d3a158a60312..b1fb7866b0b3 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -71,7 +71,7 @@ static inline void platform_finish(void)
static int prepare_processes(void)
{
- int error;
+ int error = 0;
pm_prepare_console();
@@ -84,6 +84,12 @@ static int prepare_processes(void)
goto thaw;
}
+ if (pm_disk_mode == PM_DISK_TESTPROC) {
+ printk("swsusp debug: Waiting for 5 seconds.\n");
+ mdelay(5000);
+ goto thaw;
+ }
+
/* Free memory before shutting down devices. */
if (!(error = swsusp_shrink_memory()))
return 0;
@@ -120,13 +126,21 @@ int pm_suspend_disk(void)
if (error)
return error;
+ if (pm_disk_mode == PM_DISK_TESTPROC)
+ goto Thaw;
+
suspend_console();
error = device_suspend(PMSG_FREEZE);
if (error) {
resume_console();
printk("Some devices failed to suspend\n");
- unprepare_processes();
- return error;
+ goto Thaw;
+ }
+
+ if (pm_disk_mode == PM_DISK_TEST) {
+ printk("swsusp debug: Waiting for 5 seconds.\n");
+ mdelay(5000);
+ goto Done;
}
pr_debug("PM: snapshotting memory.\n");
@@ -143,16 +157,17 @@ int pm_suspend_disk(void)
power_down(pm_disk_mode);
else {
swsusp_free();
- unprepare_processes();
- return error;
+ goto Thaw;
}
- } else
+ } else {
pr_debug("PM: Image restored successfully.\n");
+ }
swsusp_free();
Done:
device_resume();
resume_console();
+ Thaw:
unprepare_processes();
return error;
}
@@ -249,6 +264,8 @@ static const char * const pm_disk_modes[] = {
[PM_DISK_PLATFORM] = "platform",
[PM_DISK_SHUTDOWN] = "shutdown",
[PM_DISK_REBOOT] = "reboot",
+ [PM_DISK_TEST] = "test",
+ [PM_DISK_TESTPROC] = "testproc",
};
/**
@@ -303,17 +320,19 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
}
}
if (mode) {
- if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT)
+ if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT ||
+ mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) {
pm_disk_mode = mode;
- else {
+ } else {
if (pm_ops && pm_ops->enter &&
(mode == pm_ops->pm_disk_mode))
pm_disk_mode = mode;
else
error = -EINVAL;
}
- } else
+ } else {
error = -EINVAL;
+ }
pr_debug("PM: suspend-to-disk mode set to '%s'\n",
pm_disk_modes[mode]);