[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: 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>
This commit is contained in:
committed by
Linus Torvalds
parent
7d145aa3ab
commit
c5c6ba4e08
@@ -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,12 +3,15 @@
|
|||||||
|
|
||||||
#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 { \
|
||||||
|
if (pm_trace_enabled) { \
|
||||||
void *tracedata; \
|
void *tracedata; \
|
||||||
asm volatile("movl $1f,%0\n" \
|
asm volatile("movl $1f,%0\n" \
|
||||||
".section .tracedata,\"a\"\n" \
|
".section .tracedata,\"a\"\n" \
|
||||||
@@ -18,6 +21,7 @@ extern void generate_resume_trace(void *tracedata, unsigned int user);
|
|||||||
:"=r" (tracedata) \
|
:"=r" (tracedata) \
|
||||||
: "i" (__LINE__), "i" (__FILE__)); \
|
: "i" (__LINE__), "i" (__FILE__)); \
|
||||||
generate_resume_trace(tracedata, user); \
|
generate_resume_trace(tracedata, user); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@@ -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
|
|||||||
|
|
||||||
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,
|
||||||
|
Reference in New Issue
Block a user