Commit b918f6e6 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Linus Torvalds

[PATCH] swsusp: debugging

Add a swsusp debugging mode.  This does everything that's needed for a suspend
except for actually suspending.  So we can look in the log messages and work
out a) what code is being slow and b) which drivers are misbehaving.

(1)
# echo testproc > /sys/power/disk
# echo disk > /sys/power/state

This should turn off the non-boot CPU, freeze all processes, wait for 5
seconds and then thaw the processes and the CPU.

(2)
# echo test > /sys/power/disk
# echo disk > /sys/power/state

This should turn off the non-boot CPU, freeze all processes, shrink
memory, suspend all devices, wait for 5 seconds, resume the devices etc.

Cc: Pavel Machek <pavel@ucw.cz>
Cc: Stefan Seyfried <seife@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 90d53909
...@@ -21,7 +21,7 @@ Description: ...@@ -21,7 +21,7 @@ Description:
these states. these states.
What: /sys/power/disk What: /sys/power/disk
Date: August 2006 Date: September 2006
Contact: Rafael J. Wysocki <rjw@sisk.pl> Contact: Rafael J. Wysocki <rjw@sisk.pl>
Description: Description:
The /sys/power/disk file controls the operating mode of the The /sys/power/disk file controls the operating mode of the
...@@ -39,6 +39,19 @@ Description: ...@@ -39,6 +39,19 @@ Description:
'reboot' - the memory image will be saved by the kernel and 'reboot' - the memory image will be saved by the kernel and
the system will be rebooted. 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 The suspend-to-disk method may be chosen by writing to this
file one of the accepted strings: file one of the accepted strings:
...@@ -46,6 +59,8 @@ Description: ...@@ -46,6 +59,8 @@ Description:
'platform' 'platform'
'shutdown' 'shutdown'
'reboot' 'reboot'
'testproc'
'test'
It will only change to 'firmware' or 'platform' if the system It will only change to 'firmware' or 'platform' if the system
supports that. supports that.
......
...@@ -30,6 +30,17 @@ testing). The system will support either 'firmware' or 'platform', and ...@@ -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 that is known a priori. But, the user may choose 'shutdown' or
'reboot' as alternatives. '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 Reading from this file will display what the mode is currently set
to. Writing to this file will accept one of to. Writing to this file will accept one of
...@@ -37,6 +48,8 @@ to. Writing to this file will accept one of ...@@ -37,6 +48,8 @@ to. Writing to this file will accept one of
'platform' 'platform'
'shutdown' 'shutdown'
'reboot' 'reboot'
'testproc'
'test'
It will only change to 'firmware' or 'platform' if the system supports It will only change to 'firmware' or 'platform' if the system supports
it. it.
......
...@@ -116,7 +116,9 @@ typedef int __bitwise suspend_disk_method_t; ...@@ -116,7 +116,9 @@ typedef int __bitwise suspend_disk_method_t;
#define PM_DISK_PLATFORM ((__force suspend_disk_method_t) 2) #define PM_DISK_PLATFORM ((__force suspend_disk_method_t) 2)
#define PM_DISK_SHUTDOWN ((__force suspend_disk_method_t) 3) #define PM_DISK_SHUTDOWN ((__force suspend_disk_method_t) 3)
#define PM_DISK_REBOOT ((__force suspend_disk_method_t) 4) #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 { struct pm_ops {
suspend_disk_method_t pm_disk_mode; suspend_disk_method_t pm_disk_mode;
......
...@@ -71,7 +71,7 @@ static inline void platform_finish(void) ...@@ -71,7 +71,7 @@ static inline void platform_finish(void)
static int prepare_processes(void) static int prepare_processes(void)
{ {
int error; int error = 0;
pm_prepare_console(); pm_prepare_console();
...@@ -84,6 +84,12 @@ static int prepare_processes(void) ...@@ -84,6 +84,12 @@ static int prepare_processes(void)
goto thaw; 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. */ /* Free memory before shutting down devices. */
if (!(error = swsusp_shrink_memory())) if (!(error = swsusp_shrink_memory()))
return 0; return 0;
...@@ -120,13 +126,21 @@ int pm_suspend_disk(void) ...@@ -120,13 +126,21 @@ int pm_suspend_disk(void)
if (error) if (error)
return error; return error;
if (pm_disk_mode == PM_DISK_TESTPROC)
goto Thaw;
suspend_console(); suspend_console();
error = device_suspend(PMSG_FREEZE); error = device_suspend(PMSG_FREEZE);
if (error) { if (error) {
resume_console(); resume_console();
printk("Some devices failed to suspend\n"); printk("Some devices failed to suspend\n");
unprepare_processes(); goto Thaw;
return error; }
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"); pr_debug("PM: snapshotting memory.\n");
...@@ -143,16 +157,17 @@ int pm_suspend_disk(void) ...@@ -143,16 +157,17 @@ int pm_suspend_disk(void)
power_down(pm_disk_mode); power_down(pm_disk_mode);
else { else {
swsusp_free(); swsusp_free();
unprepare_processes(); goto Thaw;
return error;
} }
} else } else {
pr_debug("PM: Image restored successfully.\n"); pr_debug("PM: Image restored successfully.\n");
}
swsusp_free(); swsusp_free();
Done: Done:
device_resume(); device_resume();
resume_console(); resume_console();
Thaw:
unprepare_processes(); unprepare_processes();
return error; return error;
} }
...@@ -249,6 +264,8 @@ static const char * const pm_disk_modes[] = { ...@@ -249,6 +264,8 @@ static const char * const pm_disk_modes[] = {
[PM_DISK_PLATFORM] = "platform", [PM_DISK_PLATFORM] = "platform",
[PM_DISK_SHUTDOWN] = "shutdown", [PM_DISK_SHUTDOWN] = "shutdown",
[PM_DISK_REBOOT] = "reboot", [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) ...@@ -303,17 +320,19 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
} }
} }
if (mode) { 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; pm_disk_mode = mode;
else { } else {
if (pm_ops && pm_ops->enter && if (pm_ops && pm_ops->enter &&
(mode == pm_ops->pm_disk_mode)) (mode == pm_ops->pm_disk_mode))
pm_disk_mode = mode; pm_disk_mode = mode;
else else
error = -EINVAL; error = -EINVAL;
} }
} else } else {
error = -EINVAL; error = -EINVAL;
}
pr_debug("PM: suspend-to-disk mode set to '%s'\n", pr_debug("PM: suspend-to-disk mode set to '%s'\n",
pm_disk_modes[mode]); pm_disk_modes[mode]);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment