[PATCH] PM: Add pm_trace switch
authorRafael J. Wysocki <rjw@sisk.pl>
Tue, 26 Sep 2006 06:32:58 +0000 (23:32 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 26 Sep 2006 15:49:04 +0000 (08:49 -0700)
Add the pm_trace attribute in /sys/power which has to be explicitly set to
one to really enable the "PM tracing" code compiled in when CONFIG_PM_TRACE
is set (which modifies the machine's CMOS clock in unpredictable ways).

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Documentation/power/interface.txt
include/linux/resume-trace.h
kernel/power/main.c

index 4117802af0f8ce560316d557045566a5f0ea8494..a66bec222b16cba4caf24720da712c25a2372ed7 100644 (file)
@@ -52,3 +52,18 @@ suspend image will be as small as possible.
 
 Reading from this file will display the current image size limit, which
 is set to 500 MB by default.
+
+/sys/power/pm_trace controls the code which saves the last PM event point in
+the RTC across reboots, so that you can debug a machine that just hangs
+during suspend (or more commonly, during resume).  Namely, the RTC is only
+used to save the last PM event point if this file contains '1'.  Initially it
+contains '0' which may be changed to '1' by writing a string representing a
+nonzero integer into it.
+
+To use this debugging feature you should attempt to suspend the machine, then
+reboot it and run
+
+       dmesg -s 1000000 | grep 'hash matches'
+
+CAUTION: Using it will cause your machine's real-time (CMOS) clock to be
+set to a random invalid time after a resume.
index a376bd4ade394fb99398ad3b905e7dc9fe981656..81e9299ca148dd34d576fe5ddad660b2510c3de6 100644 (file)
@@ -3,21 +3,25 @@
 
 #ifdef CONFIG_PM_TRACE
 
+extern int pm_trace_enabled;
+
 struct device;
 extern void set_trace_device(struct device *);
 extern void generate_resume_trace(void *tracedata, unsigned int user);
 
 #define TRACE_DEVICE(dev) set_trace_device(dev)
-#define TRACE_RESUME(user) do {                                \
-       void *tracedata;                                \
-       asm volatile("movl $1f,%0\n"                    \
-               ".section .tracedata,\"a\"\n"           \
-               "1:\t.word %c1\n"                       \
-               "\t.long %c2\n"                         \
-               ".previous"                             \
-               :"=r" (tracedata)                       \
-               : "i" (__LINE__), "i" (__FILE__));      \
-       generate_resume_trace(tracedata, user);         \
+#define TRACE_RESUME(user) do {                                        \
+       if (pm_trace_enabled) {                                 \
+               void *tracedata;                                \
+               asm volatile("movl $1f,%0\n"                    \
+                       ".section .tracedata,\"a\"\n"           \
+                       "1:\t.word %c1\n"                       \
+                       "\t.long %c2\n"                         \
+                       ".previous"                             \
+                       :"=r" (tracedata)                       \
+                       : "i" (__LINE__), "i" (__FILE__));      \
+               generate_resume_trace(tracedata, user);         \
+       }                                                       \
 } while (0)
 
 #else
index 4d403323a7bb709c6384f7a5085f3cdb0872c360..873228c71dabdf700abcf2e6c19dcb3cc96315b7 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/pm.h>
 #include <linux/console.h>
 #include <linux/cpu.h>
+#include <linux/resume-trace.h>
 
 #include "power.h"
 
@@ -281,10 +282,39 @@ static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n
 
 power_attr(state);
 
+#ifdef CONFIG_PM_TRACE
+int pm_trace_enabled;
+
+static ssize_t pm_trace_show(struct subsystem * subsys, char * buf)
+{
+       return sprintf(buf, "%d\n", pm_trace_enabled);
+}
+
+static ssize_t
+pm_trace_store(struct subsystem * subsys, const char * buf, size_t n)
+{
+       int val;
+
+       if (sscanf(buf, "%d", &val) == 1) {
+               pm_trace_enabled = !!val;
+               return n;
+       }
+       return -EINVAL;
+}
+
+power_attr(pm_trace);
+
+static struct attribute * g[] = {
+       &state_attr.attr,
+       &pm_trace_attr.attr,
+       NULL,
+};
+#else
 static struct attribute * g[] = {
        &state_attr.attr,
        NULL,
 };
+#endif /* CONFIG_PM_TRACE */
 
 static struct attribute_group attr_group = {
        .attrs = g,