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

[PATCH] PM: Add pm_trace switch

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: default avatarRafael J. Wysocki <rjw@sisk.pl>
Acked-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7d145aa3
...@@ -52,3 +52,18 @@ suspend image will be as small as possible. ...@@ -52,3 +52,18 @@ suspend image will be as small as possible.
Reading from this file will display the current image size limit, which Reading from this file will display the current image size limit, which
is set to 500 MB by default. 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.
...@@ -3,21 +3,25 @@ ...@@ -3,21 +3,25 @@
#ifdef CONFIG_PM_TRACE #ifdef CONFIG_PM_TRACE
extern int pm_trace_enabled;
struct device; struct device;
extern void set_trace_device(struct device *); extern void set_trace_device(struct device *);
extern void generate_resume_trace(void *tracedata, unsigned int user); extern void generate_resume_trace(void *tracedata, unsigned int user);
#define TRACE_DEVICE(dev) set_trace_device(dev) #define TRACE_DEVICE(dev) set_trace_device(dev)
#define TRACE_RESUME(user) do { \ #define TRACE_RESUME(user) do { \
void *tracedata; \ if (pm_trace_enabled) { \
asm volatile("movl $1f,%0\n" \ void *tracedata; \
".section .tracedata,\"a\"\n" \ asm volatile("movl $1f,%0\n" \
"1:\t.word %c1\n" \ ".section .tracedata,\"a\"\n" \
"\t.long %c2\n" \ "1:\t.word %c1\n" \
".previous" \ "\t.long %c2\n" \
:"=r" (tracedata) \ ".previous" \
: "i" (__LINE__), "i" (__FILE__)); \ :"=r" (tracedata) \
generate_resume_trace(tracedata, user); \ : "i" (__LINE__), "i" (__FILE__)); \
generate_resume_trace(tracedata, user); \
} \
} while (0) } while (0)
#else #else
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/cpu.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 ...@@ -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[] = { static struct attribute * g[] = {
&state_attr.attr, &state_attr.attr,
NULL, NULL,
}; };
#endif /* CONFIG_PM_TRACE */
static struct attribute_group attr_group = { static struct attribute_group attr_group = {
.attrs = g, .attrs = g,
......
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