[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 4117802..a66bec2 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.
 
 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 a376bd4..81e9299 100644 (file)
@@ -3,21 +3,25 @@
 
 #ifdef CONFIG_PM_TRACE
 
 
 #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)
 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
 } while (0)
 
 #else
index 4d40332..873228c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/pm.h>
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/pm.h>
 #include <linux/console.h>
 #include <linux/cpu.h>
+#include <linux/resume-trace.h>
 
 #include "power.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);
 
 
 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,
 };
 static struct attribute * g[] = {
        &state_attr.attr,
        NULL,
 };
+#endif /* CONFIG_PM_TRACE */
 
 static struct attribute_group attr_group = {
        .attrs = g,
 
 static struct attribute_group attr_group = {
        .attrs = g,