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, |
