Эх сурвалжийг харах

[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: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Rafael J. Wysocki 18 жил өмнө
parent
commit
b918f6e62c

+ 16 - 1
Documentation/ABI/testing/sysfs-power

@@ -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:
 		'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:
 		'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.

+ 13 - 0
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
 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
        '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. 

+ 3 - 1
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_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;

+ 28 - 9
kernel/power/disk.c

@@ -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)
 		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)
 	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();
-		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");
 	pr_debug("PM: snapshotting memory.\n");
@@ -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();
-			return error;
+			goto Thaw;
 		}
 		}
-	} 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[] = {
 	[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)
 		}
 		}
 	}
 	}
 	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]);