aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/power/interface.txt15
-rw-r--r--include/linux/resume-trace.h24
-rw-r--r--kernel/power/main.c30
3 files changed, 59 insertions, 10 deletions
diff --git a/Documentation/power/interface.txt b/Documentation/power/interface.txt
index 4117802af0f8..a66bec222b16 100644
--- a/Documentation/power/interface.txt
+++ b/Documentation/power/interface.txt
@@ -52,3 +52,18 @@ suspend image will be as small as possible.
52 52
53Reading from this file will display the current image size limit, which 53Reading from this file will display the current image size limit, which
54is set to 500 MB by default. 54is set to 500 MB by default.
55
56/sys/power/pm_trace controls the code which saves the last PM event point in
57the RTC across reboots, so that you can debug a machine that just hangs
58during suspend (or more commonly, during resume). Namely, the RTC is only
59used to save the last PM event point if this file contains '1'. Initially it
60contains '0' which may be changed to '1' by writing a string representing a
61nonzero integer into it.
62
63To use this debugging feature you should attempt to suspend the machine, then
64reboot it and run
65
66 dmesg -s 1000000 | grep 'hash matches'
67
68CAUTION: Using it will cause your machine's real-time (CMOS) clock to be
69set to a random invalid time after a resume.
diff --git a/include/linux/resume-trace.h b/include/linux/resume-trace.h
index a376bd4ade39..81e9299ca148 100644
--- a/include/linux/resume-trace.h
+++ b/include/linux/resume-trace.h
@@ -3,21 +3,25 @@
3 3
4#ifdef CONFIG_PM_TRACE 4#ifdef CONFIG_PM_TRACE
5 5
6extern int pm_trace_enabled;
7
6struct device; 8struct device;
7extern void set_trace_device(struct device *); 9extern void set_trace_device(struct device *);
8extern void generate_resume_trace(void *tracedata, unsigned int user); 10extern void generate_resume_trace(void *tracedata, unsigned int user);
9 11
10#define TRACE_DEVICE(dev) set_trace_device(dev) 12#define TRACE_DEVICE(dev) set_trace_device(dev)
11#define TRACE_RESUME(user) do { \ 13#define TRACE_RESUME(user) do { \
12 void *tracedata; \ 14 if (pm_trace_enabled) { \
13 asm volatile("movl $1f,%0\n" \ 15 void *tracedata; \
14 ".section .tracedata,\"a\"\n" \ 16 asm volatile("movl $1f,%0\n" \
15 "1:\t.word %c1\n" \ 17 ".section .tracedata,\"a\"\n" \
16 "\t.long %c2\n" \ 18 "1:\t.word %c1\n" \
17 ".previous" \ 19 "\t.long %c2\n" \
18 :"=r" (tracedata) \ 20 ".previous" \
19 : "i" (__LINE__), "i" (__FILE__)); \ 21 :"=r" (tracedata) \
20 generate_resume_trace(tracedata, user); \ 22 : "i" (__LINE__), "i" (__FILE__)); \
23 generate_resume_trace(tracedata, user); \
24 } \
21} while (0) 25} while (0)
22 26
23#else 27#else
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 4d403323a7bb..873228c71dab 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -17,6 +17,7 @@
17#include <linux/pm.h> 17#include <linux/pm.h>
18#include <linux/console.h> 18#include <linux/console.h>
19#include <linux/cpu.h> 19#include <linux/cpu.h>
20#include <linux/resume-trace.h>
20 21
21#include "power.h" 22#include "power.h"
22 23
@@ -281,10 +282,39 @@ static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n
281 282
282power_attr(state); 283power_attr(state);
283 284
285#ifdef CONFIG_PM_TRACE
286int pm_trace_enabled;
287
288static ssize_t pm_trace_show(struct subsystem * subsys, char * buf)
289{
290 return sprintf(buf, "%d\n", pm_trace_enabled);
291}
292
293static ssize_t
294pm_trace_store(struct subsystem * subsys, const char * buf, size_t n)
295{
296 int val;
297
298 if (sscanf(buf, "%d", &val) == 1) {
299 pm_trace_enabled = !!val;
300 return n;
301 }
302 return -EINVAL;
303}
304
305power_attr(pm_trace);
306
307static struct attribute * g[] = {
308 &state_attr.attr,
309 &pm_trace_attr.attr,
310 NULL,
311};
312#else
284static struct attribute * g[] = { 313static struct attribute * g[] = {
285 &state_attr.attr, 314 &state_attr.attr,
286 NULL, 315 NULL,
287}; 316};
317#endif /* CONFIG_PM_TRACE */
288 318
289static struct attribute_group attr_group = { 319static struct attribute_group attr_group = {
290 .attrs = g, 320 .attrs = g,