diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-power | 29 | ||||
-rw-r--r-- | Documentation/power/s2ram.txt | 7 | ||||
-rw-r--r-- | drivers/base/power/trace.c | 31 | ||||
-rw-r--r-- | include/linux/resume-trace.h | 2 | ||||
-rw-r--r-- | kernel/power/main.c | 18 |
5 files changed, 87 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index 2875f1f74a07..194ca446ac28 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power | |||
@@ -99,9 +99,38 @@ Description: | |||
99 | 99 | ||
100 | dmesg -s 1000000 | grep 'hash matches' | 100 | dmesg -s 1000000 | grep 'hash matches' |
101 | 101 | ||
102 | If you do not get any matches (or they appear to be false | ||
103 | positives), it is possible that the last PM event point | ||
104 | referred to a device created by a loadable kernel module. In | ||
105 | this case cat /sys/power/pm_trace_dev_match (see below) after | ||
106 | your system is started up and the kernel modules are loaded. | ||
107 | |||
102 | CAUTION: Using it will cause your machine's real-time (CMOS) | 108 | CAUTION: Using it will cause your machine's real-time (CMOS) |
103 | clock to be set to a random invalid time after a resume. | 109 | clock to be set to a random invalid time after a resume. |
104 | 110 | ||
111 | What; /sys/power/pm_trace_dev_match | ||
112 | Date: October 2010 | ||
113 | Contact: James Hogan <james@albanarts.com> | ||
114 | Description: | ||
115 | The /sys/power/pm_trace_dev_match file contains the name of the | ||
116 | device associated with the last PM event point saved in the RTC | ||
117 | across reboots when pm_trace has been used. More precisely it | ||
118 | contains the list of current devices (including those | ||
119 | registered by loadable kernel modules since boot) which match | ||
120 | the device hash in the RTC at boot, with a newline after each | ||
121 | one. | ||
122 | |||
123 | The advantage of this file over the hash matches printed to the | ||
124 | kernel log (see /sys/power/pm_trace), is that it includes | ||
125 | devices created after boot by loadable kernel modules. | ||
126 | |||
127 | Due to the small hash size necessary to fit in the RTC, it is | ||
128 | possible that more than one device matches the hash, in which | ||
129 | case further investigation is required to determine which | ||
130 | device is causing the problem. Note that genuine RTC clock | ||
131 | values (such as when pm_trace has not been used), can still | ||
132 | match a device and output it's name here. | ||
133 | |||
105 | What: /sys/power/pm_async | 134 | What: /sys/power/pm_async |
106 | Date: January 2009 | 135 | Date: January 2009 |
107 | Contact: Rafael J. Wysocki <rjw@sisk.pl> | 136 | Contact: Rafael J. Wysocki <rjw@sisk.pl> |
diff --git a/Documentation/power/s2ram.txt b/Documentation/power/s2ram.txt index 514b94fc931e..1bdfa0443773 100644 --- a/Documentation/power/s2ram.txt +++ b/Documentation/power/s2ram.txt | |||
@@ -49,6 +49,13 @@ machine that doesn't boot) is: | |||
49 | device (lspci and /sys/devices/pci* is your friend), and see if you can | 49 | device (lspci and /sys/devices/pci* is your friend), and see if you can |
50 | fix it, disable it, or trace into its resume function. | 50 | fix it, disable it, or trace into its resume function. |
51 | 51 | ||
52 | If no device matches the hash (or any matches appear to be false positives), | ||
53 | the culprit may be a device from a loadable kernel module that is not loaded | ||
54 | until after the hash is checked. You can check the hash against the current | ||
55 | devices again after more modules are loaded using sysfs: | ||
56 | |||
57 | cat /sys/power/pm_trace_dev_match | ||
58 | |||
52 | For example, the above happens to be the VGA device on my EVO, which I | 59 | For example, the above happens to be the VGA device on my EVO, which I |
53 | used to run with "radeonfb" (it's an ATI Radeon mobility). It turns out | 60 | used to run with "radeonfb" (it's an ATI Radeon mobility). It turns out |
54 | that "radeonfb" simply cannot resume that device - it tries to set the | 61 | that "radeonfb" simply cannot resume that device - it tries to set the |
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index 17e24e3f4422..9f4258df4cfd 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c | |||
@@ -207,6 +207,37 @@ static int show_dev_hash(unsigned int value) | |||
207 | 207 | ||
208 | static unsigned int hash_value_early_read; | 208 | static unsigned int hash_value_early_read; |
209 | 209 | ||
210 | int show_trace_dev_match(char *buf, size_t size) | ||
211 | { | ||
212 | unsigned int value = hash_value_early_read / (USERHASH * FILEHASH); | ||
213 | int ret = 0; | ||
214 | struct list_head *entry; | ||
215 | |||
216 | /* | ||
217 | * It's possible that multiple devices will match the hash and we can't | ||
218 | * tell which is the culprit, so it's best to output them all. | ||
219 | */ | ||
220 | device_pm_lock(); | ||
221 | entry = dpm_list.prev; | ||
222 | while (size && entry != &dpm_list) { | ||
223 | struct device *dev = to_device(entry); | ||
224 | unsigned int hash = hash_string(DEVSEED, dev_name(dev), | ||
225 | DEVHASH); | ||
226 | if (hash == value) { | ||
227 | int len = snprintf(buf, size, "%s\n", | ||
228 | dev_driver_string(dev)); | ||
229 | if (len > size) | ||
230 | len = size; | ||
231 | buf += len; | ||
232 | ret += len; | ||
233 | size -= len; | ||
234 | } | ||
235 | entry = entry->prev; | ||
236 | } | ||
237 | device_pm_unlock(); | ||
238 | return ret; | ||
239 | } | ||
240 | |||
210 | static int early_resume_init(void) | 241 | static int early_resume_init(void) |
211 | { | 242 | { |
212 | hash_value_early_read = read_magic_time(); | 243 | hash_value_early_read = read_magic_time(); |
diff --git a/include/linux/resume-trace.h b/include/linux/resume-trace.h index bc8c3881c729..f31db2368782 100644 --- a/include/linux/resume-trace.h +++ b/include/linux/resume-trace.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #ifdef CONFIG_PM_TRACE | 4 | #ifdef CONFIG_PM_TRACE |
5 | #include <asm/resume-trace.h> | 5 | #include <asm/resume-trace.h> |
6 | #include <linux/types.h> | ||
6 | 7 | ||
7 | extern int pm_trace_enabled; | 8 | extern int pm_trace_enabled; |
8 | 9 | ||
@@ -14,6 +15,7 @@ static inline int pm_trace_is_enabled(void) | |||
14 | struct device; | 15 | struct device; |
15 | extern void set_trace_device(struct device *); | 16 | extern void set_trace_device(struct device *); |
16 | extern void generate_resume_trace(const void *tracedata, unsigned int user); | 17 | extern void generate_resume_trace(const void *tracedata, unsigned int user); |
18 | extern int show_trace_dev_match(char *buf, size_t size); | ||
17 | 19 | ||
18 | #define TRACE_DEVICE(dev) do { \ | 20 | #define TRACE_DEVICE(dev) do { \ |
19 | if (pm_trace_enabled) \ | 21 | if (pm_trace_enabled) \ |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 6b12a0cf4d9f..7b5db6a8561e 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -281,12 +281,30 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
281 | } | 281 | } |
282 | 282 | ||
283 | power_attr(pm_trace); | 283 | power_attr(pm_trace); |
284 | |||
285 | static ssize_t pm_trace_dev_match_show(struct kobject *kobj, | ||
286 | struct kobj_attribute *attr, | ||
287 | char *buf) | ||
288 | { | ||
289 | return show_trace_dev_match(buf, PAGE_SIZE); | ||
290 | } | ||
291 | |||
292 | static ssize_t | ||
293 | pm_trace_dev_match_store(struct kobject *kobj, struct kobj_attribute *attr, | ||
294 | const char *buf, size_t n) | ||
295 | { | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | power_attr(pm_trace_dev_match); | ||
300 | |||
284 | #endif /* CONFIG_PM_TRACE */ | 301 | #endif /* CONFIG_PM_TRACE */ |
285 | 302 | ||
286 | static struct attribute * g[] = { | 303 | static struct attribute * g[] = { |
287 | &state_attr.attr, | 304 | &state_attr.attr, |
288 | #ifdef CONFIG_PM_TRACE | 305 | #ifdef CONFIG_PM_TRACE |
289 | &pm_trace_attr.attr, | 306 | &pm_trace_attr.attr, |
307 | &pm_trace_dev_match_attr.attr, | ||
290 | #endif | 308 | #endif |
291 | #ifdef CONFIG_PM_SLEEP | 309 | #ifdef CONFIG_PM_SLEEP |
292 | &pm_async_attr.attr, | 310 | &pm_async_attr.attr, |