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