Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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