trace.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /*
  2. * drivers/base/power/trace.c
  3. *
  4. * Copyright (C) 2006 Linus Torvalds
  5. *
  6. * Trace facility for suspend/resume problems, when none of the
  7. * devices may be working.
  8. */
  9. #include <linux/pm-trace.h>
  10. #include <linux/export.h>
  11. #include <linux/rtc.h>
  12. #include <linux/suspend.h>
  13. #include <linux/mc146818rtc.h>
  14. #include "power.h"
  15. /*
  16. * Horrid, horrid, horrid.
  17. *
  18. * It turns out that the _only_ piece of hardware that actually
  19. * keeps its value across a hard boot (and, more importantly, the
  20. * POST init sequence) is literally the realtime clock.
  21. *
  22. * Never mind that an RTC chip has 114 bytes (and often a whole
  23. * other bank of an additional 128 bytes) of nice SRAM that is
  24. * _designed_ to keep data - the POST will clear it. So we literally
  25. * can just use the few bytes of actual time data, which means that
  26. * we're really limited.
  27. *
  28. * It means, for example, that we can't use the seconds at all
  29. * (since the time between the hang and the boot might be more
  30. * than a minute), and we'd better not depend on the low bits of
  31. * the minutes either.
  32. *
  33. * There are the wday fields etc, but I wouldn't guarantee those
  34. * are dependable either. And if the date isn't valid, either the
  35. * hw or POST will do strange things.
  36. *
  37. * So we're left with:
  38. * - year: 0-99
  39. * - month: 0-11
  40. * - day-of-month: 1-28
  41. * - hour: 0-23
  42. * - min: (0-30)*2
  43. *
  44. * Giving us a total range of 0-16128000 (0xf61800), ie less
  45. * than 24 bits of actual data we can save across reboots.
  46. *
  47. * And if your box can't boot in less than three minutes,
  48. * you're screwed.
  49. *
  50. * Now, almost 24 bits of data is pitifully small, so we need
  51. * to be pretty dense if we want to use it for anything nice.
  52. * What we do is that instead of saving off nice readable info,
  53. * we save off _hashes_ of information that we can hopefully
  54. * regenerate after the reboot.
  55. *
  56. * In particular, this means that we might be unlucky, and hit
  57. * a case where we have a hash collision, and we end up not
  58. * being able to tell for certain exactly which case happened.
  59. * But that's hopefully unlikely.
  60. *
  61. * What we do is to take the bits we can fit, and split them
  62. * into three parts (16*997*1009 = 16095568), and use the values
  63. * for:
  64. * - 0-15: user-settable
  65. * - 0-996: file + line number
  66. * - 0-1008: device
  67. */
  68. #define USERHASH (16)
  69. #define FILEHASH (997)
  70. #define DEVHASH (1009)
  71. #define DEVSEED (7919)
  72. bool pm_trace_rtc_abused __read_mostly;
  73. EXPORT_SYMBOL_GPL(pm_trace_rtc_abused);
  74. static unsigned int dev_hash_value;
  75. static int set_magic_time(unsigned int user, unsigned int file, unsigned int device)
  76. {
  77. unsigned int n = user + USERHASH*(file + FILEHASH*device);
  78. // June 7th, 2006
  79. static struct rtc_time time = {
  80. .tm_sec = 0,
  81. .tm_min = 0,
  82. .tm_hour = 0,
  83. .tm_mday = 7,
  84. .tm_mon = 5, // June - counting from zero
  85. .tm_year = 106,
  86. .tm_wday = 3,
  87. .tm_yday = 160,
  88. .tm_isdst = 1
  89. };
  90. time.tm_year = (n % 100);
  91. n /= 100;
  92. time.tm_mon = (n % 12);
  93. n /= 12;
  94. time.tm_mday = (n % 28) + 1;
  95. n /= 28;
  96. time.tm_hour = (n % 24);
  97. n /= 24;
  98. time.tm_min = (n % 20) * 3;
  99. n /= 20;
  100. mc146818_set_time(&time);
  101. pm_trace_rtc_abused = true;
  102. return n ? -1 : 0;
  103. }
  104. static unsigned int read_magic_time(void)
  105. {
  106. struct rtc_time time;
  107. unsigned int val;
  108. mc146818_get_time(&time);
  109. pr_info("RTC time: %2d:%02d:%02d, date: %02d/%02d/%02d\n",
  110. time.tm_hour, time.tm_min, time.tm_sec,
  111. time.tm_mon + 1, time.tm_mday, time.tm_year % 100);
  112. val = time.tm_year; /* 100 years */
  113. if (val > 100)
  114. val -= 100;
  115. val += time.tm_mon * 100; /* 12 months */
  116. val += (time.tm_mday-1) * 100 * 12; /* 28 month-days */
  117. val += time.tm_hour * 100 * 12 * 28; /* 24 hours */
  118. val += (time.tm_min / 3) * 100 * 12 * 28 * 24; /* 20 3-minute intervals */
  119. return val;
  120. }
  121. /*
  122. * This is just the sdbm hash function with a user-supplied
  123. * seed and final size parameter.
  124. */
  125. static unsigned int hash_string(unsigned int seed, const char *data, unsigned int mod)
  126. {
  127. unsigned char c;
  128. while ((c = *data++) != 0) {
  129. seed = (seed << 16) + (seed << 6) - seed + c;
  130. }
  131. return seed % mod;
  132. }
  133. void set_trace_device(struct device *dev)
  134. {
  135. dev_hash_value = hash_string(DEVSEED, dev_name(dev), DEVHASH);
  136. }
  137. EXPORT_SYMBOL(set_trace_device);
  138. /*
  139. * We could just take the "tracedata" index into the .tracedata
  140. * section instead. Generating a hash of the data gives us a
  141. * chance to work across kernel versions, and perhaps more
  142. * importantly it also gives us valid/invalid check (ie we will
  143. * likely not give totally bogus reports - if the hash matches,
  144. * it's not any guarantee, but it's a high _likelihood_ that
  145. * the match is valid).
  146. */
  147. void generate_pm_trace(const void *tracedata, unsigned int user)
  148. {
  149. unsigned short lineno = *(unsigned short *)tracedata;
  150. const char *file = *(const char **)(tracedata + 2);
  151. unsigned int user_hash_value, file_hash_value;
  152. user_hash_value = user % USERHASH;
  153. file_hash_value = hash_string(lineno, file, FILEHASH);
  154. set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
  155. }
  156. EXPORT_SYMBOL(generate_pm_trace);
  157. extern char __tracedata_start[], __tracedata_end[];
  158. static int show_file_hash(unsigned int value)
  159. {
  160. int match;
  161. char *tracedata;
  162. match = 0;
  163. for (tracedata = __tracedata_start ; tracedata < __tracedata_end ;
  164. tracedata += 2 + sizeof(unsigned long)) {
  165. unsigned short lineno = *(unsigned short *)tracedata;
  166. const char *file = *(const char **)(tracedata + 2);
  167. unsigned int hash = hash_string(lineno, file, FILEHASH);
  168. if (hash != value)
  169. continue;
  170. pr_info(" hash matches %s:%u\n", file, lineno);
  171. match++;
  172. }
  173. return match;
  174. }
  175. static int show_dev_hash(unsigned int value)
  176. {
  177. int match = 0;
  178. struct list_head *entry;
  179. device_pm_lock();
  180. entry = dpm_list.prev;
  181. while (entry != &dpm_list) {
  182. struct device * dev = to_device(entry);
  183. unsigned int hash = hash_string(DEVSEED, dev_name(dev), DEVHASH);
  184. if (hash == value) {
  185. dev_info(dev, "hash matches\n");
  186. match++;
  187. }
  188. entry = entry->prev;
  189. }
  190. device_pm_unlock();
  191. return match;
  192. }
  193. static unsigned int hash_value_early_read;
  194. int show_trace_dev_match(char *buf, size_t size)
  195. {
  196. unsigned int value = hash_value_early_read / (USERHASH * FILEHASH);
  197. int ret = 0;
  198. struct list_head *entry;
  199. /*
  200. * It's possible that multiple devices will match the hash and we can't
  201. * tell which is the culprit, so it's best to output them all.
  202. */
  203. device_pm_lock();
  204. entry = dpm_list.prev;
  205. while (size && entry != &dpm_list) {
  206. struct device *dev = to_device(entry);
  207. unsigned int hash = hash_string(DEVSEED, dev_name(dev),
  208. DEVHASH);
  209. if (hash == value) {
  210. int len = snprintf(buf, size, "%s\n",
  211. dev_driver_string(dev));
  212. if (len > size)
  213. len = size;
  214. buf += len;
  215. ret += len;
  216. size -= len;
  217. }
  218. entry = entry->prev;
  219. }
  220. device_pm_unlock();
  221. return ret;
  222. }
  223. static int
  224. pm_trace_notify(struct notifier_block *nb, unsigned long mode, void *_unused)
  225. {
  226. switch (mode) {
  227. case PM_POST_HIBERNATION:
  228. case PM_POST_SUSPEND:
  229. if (pm_trace_rtc_abused) {
  230. pm_trace_rtc_abused = false;
  231. pr_warn("Possible incorrect RTC due to pm_trace, please use 'ntpdate' or 'rdate' to reset it.\n");
  232. }
  233. break;
  234. default:
  235. break;
  236. }
  237. return 0;
  238. }
  239. static struct notifier_block pm_trace_nb = {
  240. .notifier_call = pm_trace_notify,
  241. };
  242. static int early_resume_init(void)
  243. {
  244. hash_value_early_read = read_magic_time();
  245. register_pm_notifier(&pm_trace_nb);
  246. return 0;
  247. }
  248. static int late_resume_init(void)
  249. {
  250. unsigned int val = hash_value_early_read;
  251. unsigned int user, file, dev;
  252. user = val % USERHASH;
  253. val = val / USERHASH;
  254. file = val % FILEHASH;
  255. val = val / FILEHASH;
  256. dev = val /* % DEVHASH */;
  257. pr_info(" Magic number: %d:%d:%d\n", user, file, dev);
  258. show_file_hash(file);
  259. show_dev_hash(dev);
  260. return 0;
  261. }
  262. core_initcall(early_resume_init);
  263. late_initcall(late_resume_init);