fmpm.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * FRU (Field-Replaceable Unit) Memory Poison Manager
  4. *
  5. * Copyright (c) 2024, Advanced Micro Devices, Inc.
  6. * All Rights Reserved.
  7. *
  8. * Authors:
  9. * Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>
  10. * Muralidhara M K <muralidhara.mk@amd.com>
  11. * Yazen Ghannam <Yazen.Ghannam@amd.com>
  12. *
  13. * Implementation notes, assumptions, and limitations:
  14. *
  15. * - FRU memory poison section and memory poison descriptor definitions are not yet
  16. * included in the UEFI specification. So they are defined here. Afterwards, they
  17. * may be moved to linux/cper.h, if appropriate.
  18. *
  19. * - Platforms based on AMD MI300 systems will be the first to use these structures.
  20. * There are a number of assumptions made here that will need to be generalized
  21. * to support other platforms.
  22. *
  23. * AMD MI300-based platform(s) assumptions:
  24. * - Memory errors are reported through x86 MCA.
  25. * - The entire DRAM row containing a memory error should be retired.
  26. * - There will be (1) FRU memory poison section per CPER.
  27. * - The FRU will be the CPU package (processor socket).
  28. * - The default number of memory poison descriptor entries should be (8).
  29. * - The platform will use ACPI ERST for persistent storage.
  30. * - All FRU records should be saved to persistent storage. Module init will
  31. * fail if any FRU record is not successfully written.
  32. *
  33. * - Boot time memory retirement may occur later than ideal due to dependencies
  34. * on other libraries and drivers. This leaves a gap where bad memory may be
  35. * accessed during early boot stages.
  36. *
  37. * - Enough memory should be pre-allocated for each FRU record to be able to hold
  38. * the expected number of descriptor entries. This, mostly empty, record is
  39. * written to storage during init time. Subsequent writes to the same record
  40. * should allow the Platform to update the stored record in-place. Otherwise,
  41. * if the record is extended, then the Platform may need to perform costly memory
  42. * management operations on the storage. For example, the Platform may spend time
  43. * in Firmware copying and invalidating memory on a relatively slow SPI ROM.
  44. */
  45. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  46. #include <linux/cper.h>
  47. #include <linux/ras.h>
  48. #include <linux/cpu.h>
  49. #include <acpi/apei.h>
  50. #include <asm/cpu_device_id.h>
  51. #include <asm/mce.h>
  52. #include "../debugfs.h"
  53. #include "atl/internal.h"
  54. #define INVALID_CPU UINT_MAX
  55. /* Validation Bits */
  56. #define FMP_VALID_ARCH_TYPE BIT_ULL(0)
  57. #define FMP_VALID_ARCH BIT_ULL(1)
  58. #define FMP_VALID_ID_TYPE BIT_ULL(2)
  59. #define FMP_VALID_ID BIT_ULL(3)
  60. #define FMP_VALID_LIST_ENTRIES BIT_ULL(4)
  61. #define FMP_VALID_LIST BIT_ULL(5)
  62. /* FRU Architecture Types */
  63. #define FMP_ARCH_TYPE_X86_CPUID_1_EAX 0
  64. /* FRU ID Types */
  65. #define FMP_ID_TYPE_X86_PPIN 0
  66. /* FRU Memory Poison Section */
  67. struct cper_sec_fru_mem_poison {
  68. u32 checksum;
  69. u64 validation_bits;
  70. u32 fru_arch_type;
  71. u64 fru_arch;
  72. u32 fru_id_type;
  73. u64 fru_id;
  74. u32 nr_entries;
  75. } __packed;
  76. /* FRU Descriptor ID Types */
  77. #define FPD_HW_ID_TYPE_MCA_IPID 0
  78. /* FRU Descriptor Address Types */
  79. #define FPD_ADDR_TYPE_MCA_ADDR 0
  80. /* Memory Poison Descriptor */
  81. struct cper_fru_poison_desc {
  82. u64 timestamp;
  83. u32 hw_id_type;
  84. u64 hw_id;
  85. u32 addr_type;
  86. u64 addr;
  87. } __packed;
  88. /* Collection of headers and sections for easy pointer use. */
  89. struct fru_rec {
  90. struct cper_record_header hdr;
  91. struct cper_section_descriptor sec_desc;
  92. struct cper_sec_fru_mem_poison fmp;
  93. struct cper_fru_poison_desc entries[];
  94. } __packed;
  95. /*
  96. * Pointers to the complete CPER record of each FRU.
  97. *
  98. * Memory allocation will include padded space for descriptor entries.
  99. */
  100. static struct fru_rec **fru_records;
  101. /* system physical addresses array */
  102. static u64 *spa_entries;
  103. static struct dentry *fmpm_dfs_dir;
  104. static struct dentry *fmpm_dfs_entries;
  105. #define CPER_CREATOR_FMP \
  106. GUID_INIT(0xcd5c2993, 0xf4b2, 0x41b2, 0xb5, 0xd4, 0xf9, 0xc3, \
  107. 0xa0, 0x33, 0x08, 0x75)
  108. #define CPER_SECTION_TYPE_FMP \
  109. GUID_INIT(0x5e4706c1, 0x5356, 0x48c6, 0x93, 0x0b, 0x52, 0xf2, \
  110. 0x12, 0x0a, 0x44, 0x58)
  111. /**
  112. * DOC: max_nr_entries (byte)
  113. * Maximum number of descriptor entries possible for each FRU.
  114. *
  115. * Values between '1' and '255' are valid.
  116. * No input or '0' will default to FMPM_DEFAULT_MAX_NR_ENTRIES.
  117. */
  118. static u8 max_nr_entries;
  119. module_param(max_nr_entries, byte, 0644);
  120. MODULE_PARM_DESC(max_nr_entries,
  121. "Maximum number of memory poison descriptor entries per FRU");
  122. #define FMPM_DEFAULT_MAX_NR_ENTRIES 8
  123. /* Maximum number of FRUs in the system. */
  124. #define FMPM_MAX_NR_FRU 256
  125. static unsigned int max_nr_fru;
  126. /* Total length of record including headers and list of descriptor entries. */
  127. static size_t max_rec_len;
  128. #define FMPM_MAX_REC_LEN (sizeof(struct fru_rec) + (sizeof(struct cper_fru_poison_desc) * 255))
  129. /* Total number of SPA entries across all FRUs. */
  130. static unsigned int spa_nr_entries;
  131. /*
  132. * Protect the local records cache in fru_records and prevent concurrent
  133. * writes to storage. This is only needed after init once notifier block
  134. * registration is done.
  135. *
  136. * The majority of a record is fixed at module init and will not change
  137. * during run time. The entries within a record will be updated as new
  138. * errors are reported. The mutex should be held whenever the entries are
  139. * accessed during run time.
  140. */
  141. static DEFINE_MUTEX(fmpm_update_mutex);
  142. #define for_each_fru(i, rec) \
  143. for (i = 0; rec = fru_records[i], i < max_nr_fru; i++)
  144. static inline u32 get_fmp_len(struct fru_rec *rec)
  145. {
  146. return rec->sec_desc.section_length - sizeof(struct cper_section_descriptor);
  147. }
  148. static struct fru_rec *get_fru_record(u64 fru_id)
  149. {
  150. struct fru_rec *rec;
  151. unsigned int i;
  152. for_each_fru(i, rec) {
  153. if (rec->fmp.fru_id == fru_id)
  154. return rec;
  155. }
  156. pr_debug("Record not found for FRU 0x%016llx\n", fru_id);
  157. return NULL;
  158. }
  159. /*
  160. * Sum up all bytes within the FRU Memory Poison Section including the Memory
  161. * Poison Descriptor entries.
  162. *
  163. * Don't include the old checksum here. It's a u32 value, so summing each of its
  164. * bytes will give the wrong total.
  165. */
  166. static u32 do_fmp_checksum(struct cper_sec_fru_mem_poison *fmp, u32 len)
  167. {
  168. u32 checksum = 0;
  169. u8 *buf, *end;
  170. /* Skip old checksum. */
  171. buf = (u8 *)fmp + sizeof(u32);
  172. end = buf + len;
  173. while (buf < end)
  174. checksum += (u8)(*(buf++));
  175. return checksum;
  176. }
  177. static int update_record_on_storage(struct fru_rec *rec)
  178. {
  179. u32 len, checksum;
  180. int ret;
  181. /* Calculate a new checksum. */
  182. len = get_fmp_len(rec);
  183. /* Get the current total. */
  184. checksum = do_fmp_checksum(&rec->fmp, len);
  185. /* Use the complement value. */
  186. rec->fmp.checksum = -checksum;
  187. pr_debug("Writing to storage\n");
  188. ret = erst_write(&rec->hdr);
  189. if (ret) {
  190. pr_warn("Storage update failed for FRU 0x%016llx\n", rec->fmp.fru_id);
  191. if (ret == -ENOSPC)
  192. pr_warn("Not enough space on storage\n");
  193. }
  194. return ret;
  195. }
  196. static bool rec_has_valid_entries(struct fru_rec *rec)
  197. {
  198. if (!(rec->fmp.validation_bits & FMP_VALID_LIST_ENTRIES))
  199. return false;
  200. if (!(rec->fmp.validation_bits & FMP_VALID_LIST))
  201. return false;
  202. return true;
  203. }
  204. /*
  205. * Row retirement is done on MI300 systems, and some bits are 'don't
  206. * care' for comparing addresses with unique physical rows. This
  207. * includes all column bits and the row[13] bit.
  208. */
  209. #define MASK_ADDR(addr) ((addr) & ~(MI300_UMC_MCA_ROW13 | MI300_UMC_MCA_COL))
  210. static bool fpds_equal(struct cper_fru_poison_desc *old, struct cper_fru_poison_desc *new)
  211. {
  212. /*
  213. * Ignore timestamp field.
  214. * The same physical error may be reported multiple times due to stuck bits, etc.
  215. *
  216. * Also, order the checks from most->least likely to fail to shortcut the code.
  217. */
  218. if (MASK_ADDR(old->addr) != MASK_ADDR(new->addr))
  219. return false;
  220. if (old->hw_id != new->hw_id)
  221. return false;
  222. if (old->addr_type != new->addr_type)
  223. return false;
  224. if (old->hw_id_type != new->hw_id_type)
  225. return false;
  226. return true;
  227. }
  228. static bool rec_has_fpd(struct fru_rec *rec, struct cper_fru_poison_desc *fpd)
  229. {
  230. unsigned int i;
  231. for (i = 0; i < rec->fmp.nr_entries; i++) {
  232. struct cper_fru_poison_desc *fpd_i = &rec->entries[i];
  233. if (fpds_equal(fpd_i, fpd)) {
  234. pr_debug("Found duplicate record\n");
  235. return true;
  236. }
  237. }
  238. return false;
  239. }
  240. static void save_spa(struct fru_rec *rec, unsigned int entry,
  241. u64 addr, u64 id, unsigned int cpu)
  242. {
  243. unsigned int i, fru_idx, spa_entry;
  244. struct atl_err a_err;
  245. unsigned long spa;
  246. if (entry >= max_nr_entries) {
  247. pr_warn_once("FRU descriptor entry %d out-of-bounds (max: %d)\n",
  248. entry, max_nr_entries);
  249. return;
  250. }
  251. /* spa_nr_entries is always multiple of max_nr_entries */
  252. for (i = 0; i < spa_nr_entries; i += max_nr_entries) {
  253. fru_idx = i / max_nr_entries;
  254. if (fru_records[fru_idx] == rec)
  255. break;
  256. }
  257. if (i >= spa_nr_entries) {
  258. pr_warn_once("FRU record %d not found\n", i);
  259. return;
  260. }
  261. spa_entry = i + entry;
  262. if (spa_entry >= spa_nr_entries) {
  263. pr_warn_once("spa_entries[] index out-of-bounds\n");
  264. return;
  265. }
  266. memset(&a_err, 0, sizeof(struct atl_err));
  267. a_err.addr = addr;
  268. a_err.ipid = id;
  269. a_err.cpu = cpu;
  270. spa = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
  271. if (IS_ERR_VALUE(spa)) {
  272. pr_debug("Failed to get system address\n");
  273. return;
  274. }
  275. spa_entries[spa_entry] = spa;
  276. pr_debug("fru_idx: %u, entry: %u, spa_entry: %u, spa: 0x%016llx\n",
  277. fru_idx, entry, spa_entry, spa_entries[spa_entry]);
  278. }
  279. static void update_fru_record(struct fru_rec *rec, struct mce *m)
  280. {
  281. struct cper_sec_fru_mem_poison *fmp = &rec->fmp;
  282. struct cper_fru_poison_desc fpd, *fpd_dest;
  283. u32 entry = 0;
  284. mutex_lock(&fmpm_update_mutex);
  285. memset(&fpd, 0, sizeof(struct cper_fru_poison_desc));
  286. fpd.timestamp = m->time;
  287. fpd.hw_id_type = FPD_HW_ID_TYPE_MCA_IPID;
  288. fpd.hw_id = m->ipid;
  289. fpd.addr_type = FPD_ADDR_TYPE_MCA_ADDR;
  290. fpd.addr = m->addr;
  291. /* This is the first entry, so just save it. */
  292. if (!rec_has_valid_entries(rec))
  293. goto save_fpd;
  294. /* Ignore already recorded errors. */
  295. if (rec_has_fpd(rec, &fpd))
  296. goto out_unlock;
  297. if (rec->fmp.nr_entries >= max_nr_entries) {
  298. pr_warn("Exceeded number of entries for FRU 0x%016llx\n", rec->fmp.fru_id);
  299. goto out_unlock;
  300. }
  301. entry = fmp->nr_entries;
  302. save_fpd:
  303. save_spa(rec, entry, m->addr, m->ipid, m->extcpu);
  304. fpd_dest = &rec->entries[entry];
  305. memcpy(fpd_dest, &fpd, sizeof(struct cper_fru_poison_desc));
  306. fmp->nr_entries = entry + 1;
  307. fmp->validation_bits |= FMP_VALID_LIST_ENTRIES;
  308. fmp->validation_bits |= FMP_VALID_LIST;
  309. pr_debug("Updated FRU 0x%016llx entry #%u\n", fmp->fru_id, entry);
  310. update_record_on_storage(rec);
  311. out_unlock:
  312. mutex_unlock(&fmpm_update_mutex);
  313. }
  314. static void retire_dram_row(u64 addr, u64 id, u32 cpu)
  315. {
  316. struct atl_err a_err;
  317. memset(&a_err, 0, sizeof(struct atl_err));
  318. a_err.addr = addr;
  319. a_err.ipid = id;
  320. a_err.cpu = cpu;
  321. amd_retire_dram_row(&a_err);
  322. }
  323. static int fru_handle_mem_poison(struct notifier_block *nb, unsigned long val, void *data)
  324. {
  325. struct mce *m = (struct mce *)data;
  326. struct fru_rec *rec;
  327. if (!mce_is_memory_error(m))
  328. return NOTIFY_DONE;
  329. retire_dram_row(m->addr, m->ipid, m->extcpu);
  330. /*
  331. * An invalid FRU ID should not happen on real errors. But it
  332. * could happen from software error injection, etc.
  333. */
  334. rec = get_fru_record(m->ppin);
  335. if (!rec)
  336. return NOTIFY_DONE;
  337. update_fru_record(rec, m);
  338. return NOTIFY_OK;
  339. }
  340. static struct notifier_block fru_mem_poison_nb = {
  341. .notifier_call = fru_handle_mem_poison,
  342. .priority = MCE_PRIO_LOWEST,
  343. };
  344. static void retire_mem_fmp(struct fru_rec *rec)
  345. {
  346. struct cper_sec_fru_mem_poison *fmp = &rec->fmp;
  347. unsigned int i, cpu;
  348. for (i = 0; i < fmp->nr_entries; i++) {
  349. struct cper_fru_poison_desc *fpd = &rec->entries[i];
  350. unsigned int err_cpu = INVALID_CPU;
  351. if (fpd->hw_id_type != FPD_HW_ID_TYPE_MCA_IPID)
  352. continue;
  353. if (fpd->addr_type != FPD_ADDR_TYPE_MCA_ADDR)
  354. continue;
  355. cpus_read_lock();
  356. for_each_online_cpu(cpu) {
  357. if (topology_ppin(cpu) == fmp->fru_id) {
  358. err_cpu = cpu;
  359. break;
  360. }
  361. }
  362. cpus_read_unlock();
  363. if (err_cpu == INVALID_CPU)
  364. continue;
  365. retire_dram_row(fpd->addr, fpd->hw_id, err_cpu);
  366. save_spa(rec, i, fpd->addr, fpd->hw_id, err_cpu);
  367. }
  368. }
  369. static void retire_mem_records(void)
  370. {
  371. struct fru_rec *rec;
  372. unsigned int i;
  373. for_each_fru(i, rec) {
  374. if (!rec_has_valid_entries(rec))
  375. continue;
  376. retire_mem_fmp(rec);
  377. }
  378. }
  379. /* Set the CPER Record Header and CPER Section Descriptor fields. */
  380. static void set_rec_fields(struct fru_rec *rec)
  381. {
  382. struct cper_section_descriptor *sec_desc = &rec->sec_desc;
  383. struct cper_record_header *hdr = &rec->hdr;
  384. /*
  385. * This is a saved record created with fewer max_nr_entries.
  386. * Update the record lengths and keep everything else as-is.
  387. */
  388. if (hdr->record_length && hdr->record_length < max_rec_len) {
  389. pr_debug("Growing record 0x%016llx from %u to %zu bytes\n",
  390. hdr->record_id, hdr->record_length, max_rec_len);
  391. goto update_lengths;
  392. }
  393. memcpy(hdr->signature, CPER_SIG_RECORD, CPER_SIG_SIZE);
  394. hdr->revision = CPER_RECORD_REV;
  395. hdr->signature_end = CPER_SIG_END;
  396. /*
  397. * Currently, it is assumed that there is one FRU Memory Poison
  398. * section per CPER. But this may change for other implementations.
  399. */
  400. hdr->section_count = 1;
  401. /* The logged errors are recoverable. Otherwise, they'd never make it here. */
  402. hdr->error_severity = CPER_SEV_RECOVERABLE;
  403. hdr->validation_bits = 0;
  404. hdr->creator_id = CPER_CREATOR_FMP;
  405. hdr->notification_type = CPER_NOTIFY_MCE;
  406. hdr->record_id = cper_next_record_id();
  407. hdr->flags = CPER_HW_ERROR_FLAGS_PREVERR;
  408. sec_desc->section_offset = sizeof(struct cper_record_header);
  409. sec_desc->revision = CPER_SEC_REV;
  410. sec_desc->validation_bits = 0;
  411. sec_desc->flags = CPER_SEC_PRIMARY;
  412. sec_desc->section_type = CPER_SECTION_TYPE_FMP;
  413. sec_desc->section_severity = CPER_SEV_RECOVERABLE;
  414. update_lengths:
  415. hdr->record_length = max_rec_len;
  416. sec_desc->section_length = max_rec_len - sizeof(struct cper_record_header);
  417. }
  418. static int save_new_records(void)
  419. {
  420. DECLARE_BITMAP(new_records, FMPM_MAX_NR_FRU);
  421. struct fru_rec *rec;
  422. unsigned int i;
  423. int ret = 0;
  424. for_each_fru(i, rec) {
  425. /* No need to update saved records that match the current record size. */
  426. if (rec->hdr.record_length == max_rec_len)
  427. continue;
  428. if (!rec->hdr.record_length)
  429. set_bit(i, new_records);
  430. set_rec_fields(rec);
  431. ret = update_record_on_storage(rec);
  432. if (ret)
  433. goto out_clear;
  434. }
  435. return ret;
  436. out_clear:
  437. for_each_fru(i, rec) {
  438. if (!test_bit(i, new_records))
  439. continue;
  440. erst_clear(rec->hdr.record_id);
  441. }
  442. return ret;
  443. }
  444. /* Check that the record matches expected types for the current system.*/
  445. static bool fmp_is_usable(struct fru_rec *rec)
  446. {
  447. struct cper_sec_fru_mem_poison *fmp = &rec->fmp;
  448. u64 cpuid;
  449. pr_debug("Validation bits: 0x%016llx\n", fmp->validation_bits);
  450. if (!(fmp->validation_bits & FMP_VALID_ARCH_TYPE)) {
  451. pr_debug("Arch type unknown\n");
  452. return false;
  453. }
  454. if (fmp->fru_arch_type != FMP_ARCH_TYPE_X86_CPUID_1_EAX) {
  455. pr_debug("Arch type not 'x86 Family/Model/Stepping'\n");
  456. return false;
  457. }
  458. if (!(fmp->validation_bits & FMP_VALID_ARCH)) {
  459. pr_debug("Arch value unknown\n");
  460. return false;
  461. }
  462. cpuid = cpuid_eax(1);
  463. if (fmp->fru_arch != cpuid) {
  464. pr_debug("Arch value mismatch: record = 0x%016llx, system = 0x%016llx\n",
  465. fmp->fru_arch, cpuid);
  466. return false;
  467. }
  468. if (!(fmp->validation_bits & FMP_VALID_ID_TYPE)) {
  469. pr_debug("FRU ID type unknown\n");
  470. return false;
  471. }
  472. if (fmp->fru_id_type != FMP_ID_TYPE_X86_PPIN) {
  473. pr_debug("FRU ID type is not 'x86 PPIN'\n");
  474. return false;
  475. }
  476. if (!(fmp->validation_bits & FMP_VALID_ID)) {
  477. pr_debug("FRU ID value unknown\n");
  478. return false;
  479. }
  480. return true;
  481. }
  482. static bool fmp_is_valid(struct fru_rec *rec)
  483. {
  484. struct cper_sec_fru_mem_poison *fmp = &rec->fmp;
  485. u32 checksum, len;
  486. len = get_fmp_len(rec);
  487. if (len < sizeof(struct cper_sec_fru_mem_poison)) {
  488. pr_debug("fmp length is too small\n");
  489. return false;
  490. }
  491. /* Checksum must sum to zero for the entire section. */
  492. checksum = do_fmp_checksum(fmp, len) + fmp->checksum;
  493. if (checksum) {
  494. pr_debug("fmp checksum failed: sum = 0x%x\n", checksum);
  495. print_hex_dump_debug("fmp record: ", DUMP_PREFIX_NONE, 16, 1, fmp, len, false);
  496. return false;
  497. }
  498. if (!fmp_is_usable(rec))
  499. return false;
  500. return true;
  501. }
  502. static struct fru_rec *get_valid_record(struct fru_rec *old)
  503. {
  504. struct fru_rec *new;
  505. if (!fmp_is_valid(old)) {
  506. pr_debug("Ignoring invalid record\n");
  507. return NULL;
  508. }
  509. new = get_fru_record(old->fmp.fru_id);
  510. if (!new)
  511. pr_debug("Ignoring record for absent FRU\n");
  512. return new;
  513. }
  514. /*
  515. * Fetch saved records from persistent storage.
  516. *
  517. * For each found record:
  518. * - If it was not created by this module, then ignore it.
  519. * - If it is valid, then copy its data to the local cache.
  520. * - If it is not valid, then erase it.
  521. */
  522. static int get_saved_records(void)
  523. {
  524. struct fru_rec *old, *new;
  525. u64 record_id;
  526. int ret, pos;
  527. ssize_t len;
  528. old = kmalloc(FMPM_MAX_REC_LEN, GFP_KERNEL);
  529. if (!old) {
  530. ret = -ENOMEM;
  531. goto out;
  532. }
  533. ret = erst_get_record_id_begin(&pos);
  534. if (ret < 0)
  535. goto out_end;
  536. while (!erst_get_record_id_next(&pos, &record_id)) {
  537. if (record_id == APEI_ERST_INVALID_RECORD_ID)
  538. goto out_end;
  539. /*
  540. * Make sure to clear temporary buffer between reads to avoid
  541. * leftover data from records of various sizes.
  542. */
  543. memset(old, 0, FMPM_MAX_REC_LEN);
  544. len = erst_read_record(record_id, &old->hdr, FMPM_MAX_REC_LEN,
  545. sizeof(struct fru_rec), &CPER_CREATOR_FMP);
  546. if (len < 0)
  547. continue;
  548. new = get_valid_record(old);
  549. if (!new) {
  550. erst_clear(record_id);
  551. continue;
  552. }
  553. if (len > max_rec_len) {
  554. unsigned int saved_nr_entries;
  555. saved_nr_entries = len - sizeof(struct fru_rec);
  556. saved_nr_entries /= sizeof(struct cper_fru_poison_desc);
  557. pr_warn("Saved record found with %u entries.\n", saved_nr_entries);
  558. pr_warn("Please increase max_nr_entries to %u.\n", saved_nr_entries);
  559. ret = -EINVAL;
  560. goto out_end;
  561. }
  562. /* Restore the record */
  563. memcpy(new, old, len);
  564. }
  565. out_end:
  566. erst_get_record_id_end();
  567. kfree(old);
  568. out:
  569. return ret;
  570. }
  571. static void set_fmp_fields(struct fru_rec *rec, unsigned int cpu)
  572. {
  573. struct cper_sec_fru_mem_poison *fmp = &rec->fmp;
  574. fmp->fru_arch_type = FMP_ARCH_TYPE_X86_CPUID_1_EAX;
  575. fmp->validation_bits |= FMP_VALID_ARCH_TYPE;
  576. /* Assume all CPUs in the system have the same value for now. */
  577. fmp->fru_arch = cpuid_eax(1);
  578. fmp->validation_bits |= FMP_VALID_ARCH;
  579. fmp->fru_id_type = FMP_ID_TYPE_X86_PPIN;
  580. fmp->validation_bits |= FMP_VALID_ID_TYPE;
  581. fmp->fru_id = topology_ppin(cpu);
  582. fmp->validation_bits |= FMP_VALID_ID;
  583. }
  584. static int init_fmps(void)
  585. {
  586. struct fru_rec *rec;
  587. unsigned int i, cpu;
  588. int ret = 0;
  589. for_each_fru(i, rec) {
  590. unsigned int fru_cpu = INVALID_CPU;
  591. cpus_read_lock();
  592. for_each_online_cpu(cpu) {
  593. if (topology_physical_package_id(cpu) == i) {
  594. fru_cpu = cpu;
  595. break;
  596. }
  597. }
  598. cpus_read_unlock();
  599. if (fru_cpu == INVALID_CPU) {
  600. pr_debug("Failed to find matching CPU for FRU #%u\n", i);
  601. ret = -ENODEV;
  602. break;
  603. }
  604. set_fmp_fields(rec, fru_cpu);
  605. }
  606. return ret;
  607. }
  608. static int get_system_info(void)
  609. {
  610. /* Only load on MI300A systems for now. */
  611. if (!(boot_cpu_data.x86_model >= 0x90 &&
  612. boot_cpu_data.x86_model <= 0x9f))
  613. return -ENODEV;
  614. if (!cpu_feature_enabled(X86_FEATURE_AMD_PPIN)) {
  615. pr_debug("PPIN feature not available\n");
  616. return -ENODEV;
  617. }
  618. /* Use CPU socket as FRU for MI300 systems. */
  619. max_nr_fru = topology_max_packages();
  620. if (!max_nr_fru)
  621. return -ENODEV;
  622. if (max_nr_fru > FMPM_MAX_NR_FRU) {
  623. pr_warn("Too many FRUs to manage: found: %u, max: %u\n",
  624. max_nr_fru, FMPM_MAX_NR_FRU);
  625. return -ENODEV;
  626. }
  627. if (!max_nr_entries)
  628. max_nr_entries = FMPM_DEFAULT_MAX_NR_ENTRIES;
  629. spa_nr_entries = max_nr_fru * max_nr_entries;
  630. max_rec_len = sizeof(struct fru_rec);
  631. max_rec_len += sizeof(struct cper_fru_poison_desc) * max_nr_entries;
  632. pr_info("max FRUs: %u, max entries: %u, max record length: %lu\n",
  633. max_nr_fru, max_nr_entries, max_rec_len);
  634. return 0;
  635. }
  636. static void free_records(void)
  637. {
  638. struct fru_rec *rec;
  639. int i;
  640. for_each_fru(i, rec)
  641. kfree(rec);
  642. kfree(fru_records);
  643. kfree(spa_entries);
  644. }
  645. static int allocate_records(void)
  646. {
  647. int i, ret = 0;
  648. fru_records = kzalloc_objs(struct fru_rec *, max_nr_fru);
  649. if (!fru_records) {
  650. ret = -ENOMEM;
  651. goto out;
  652. }
  653. for (i = 0; i < max_nr_fru; i++) {
  654. fru_records[i] = kzalloc(max_rec_len, GFP_KERNEL);
  655. if (!fru_records[i]) {
  656. ret = -ENOMEM;
  657. goto out_free;
  658. }
  659. }
  660. spa_entries = kcalloc(spa_nr_entries, sizeof(u64), GFP_KERNEL);
  661. if (!spa_entries) {
  662. ret = -ENOMEM;
  663. goto out_free;
  664. }
  665. for (i = 0; i < spa_nr_entries; i++)
  666. spa_entries[i] = INVALID_SPA;
  667. return ret;
  668. out_free:
  669. while (--i >= 0)
  670. kfree(fru_records[i]);
  671. kfree(fru_records);
  672. out:
  673. return ret;
  674. }
  675. static void *fmpm_start(struct seq_file *f, loff_t *pos)
  676. {
  677. if (*pos >= (spa_nr_entries + 1))
  678. return NULL;
  679. return pos;
  680. }
  681. static void *fmpm_next(struct seq_file *f, void *data, loff_t *pos)
  682. {
  683. if (++(*pos) >= (spa_nr_entries + 1))
  684. return NULL;
  685. return pos;
  686. }
  687. static void fmpm_stop(struct seq_file *f, void *data)
  688. {
  689. }
  690. #define SHORT_WIDTH 8
  691. #define U64_WIDTH 18
  692. #define TIMESTAMP_WIDTH 19
  693. #define LONG_WIDTH 24
  694. #define U64_PAD (LONG_WIDTH - U64_WIDTH)
  695. #define TS_PAD (LONG_WIDTH - TIMESTAMP_WIDTH)
  696. static int fmpm_show(struct seq_file *f, void *data)
  697. {
  698. unsigned int fru_idx, entry, spa_entry, line;
  699. struct cper_fru_poison_desc *fpd;
  700. struct fru_rec *rec;
  701. line = *(loff_t *)data;
  702. if (line == 0) {
  703. seq_printf(f, "%-*s", SHORT_WIDTH, "fru_idx");
  704. seq_printf(f, "%-*s", LONG_WIDTH, "fru_id");
  705. seq_printf(f, "%-*s", SHORT_WIDTH, "entry");
  706. seq_printf(f, "%-*s", LONG_WIDTH, "timestamp");
  707. seq_printf(f, "%-*s", LONG_WIDTH, "hw_id");
  708. seq_printf(f, "%-*s", LONG_WIDTH, "addr");
  709. seq_printf(f, "%-*s", LONG_WIDTH, "spa");
  710. goto out_newline;
  711. }
  712. spa_entry = line - 1;
  713. fru_idx = spa_entry / max_nr_entries;
  714. entry = spa_entry % max_nr_entries;
  715. rec = fru_records[fru_idx];
  716. if (!rec)
  717. goto out;
  718. seq_printf(f, "%-*u", SHORT_WIDTH, fru_idx);
  719. seq_printf(f, "0x%016llx%-*s", rec->fmp.fru_id, U64_PAD, "");
  720. seq_printf(f, "%-*u", SHORT_WIDTH, entry);
  721. mutex_lock(&fmpm_update_mutex);
  722. if (entry >= rec->fmp.nr_entries) {
  723. seq_printf(f, "%-*s", LONG_WIDTH, "*");
  724. seq_printf(f, "%-*s", LONG_WIDTH, "*");
  725. seq_printf(f, "%-*s", LONG_WIDTH, "*");
  726. seq_printf(f, "%-*s", LONG_WIDTH, "*");
  727. goto out_unlock;
  728. }
  729. fpd = &rec->entries[entry];
  730. seq_printf(f, "%ptT%-*s", &fpd->timestamp, TS_PAD, "");
  731. seq_printf(f, "0x%016llx%-*s", fpd->hw_id, U64_PAD, "");
  732. seq_printf(f, "0x%016llx%-*s", fpd->addr, U64_PAD, "");
  733. if (spa_entries[spa_entry] == INVALID_SPA)
  734. seq_printf(f, "%-*s", LONG_WIDTH, "*");
  735. else
  736. seq_printf(f, "0x%016llx%-*s", spa_entries[spa_entry], U64_PAD, "");
  737. out_unlock:
  738. mutex_unlock(&fmpm_update_mutex);
  739. out_newline:
  740. seq_putc(f, '\n');
  741. out:
  742. return 0;
  743. }
  744. static const struct seq_operations fmpm_seq_ops = {
  745. .start = fmpm_start,
  746. .next = fmpm_next,
  747. .stop = fmpm_stop,
  748. .show = fmpm_show,
  749. };
  750. static int fmpm_open(struct inode *inode, struct file *file)
  751. {
  752. return seq_open(file, &fmpm_seq_ops);
  753. }
  754. static const struct file_operations fmpm_fops = {
  755. .open = fmpm_open,
  756. .release = seq_release,
  757. .read = seq_read,
  758. .llseek = seq_lseek,
  759. };
  760. static void setup_debugfs(void)
  761. {
  762. struct dentry *dfs = ras_get_debugfs_root();
  763. if (!dfs)
  764. return;
  765. fmpm_dfs_dir = debugfs_create_dir("fmpm", dfs);
  766. if (!fmpm_dfs_dir)
  767. return;
  768. fmpm_dfs_entries = debugfs_create_file("entries", 0400, fmpm_dfs_dir, NULL, &fmpm_fops);
  769. if (!fmpm_dfs_entries)
  770. debugfs_remove(fmpm_dfs_dir);
  771. }
  772. static const struct x86_cpu_id fmpm_cpuids[] = {
  773. X86_MATCH_VENDOR_FAM(AMD, 0x19, NULL),
  774. { }
  775. };
  776. MODULE_DEVICE_TABLE(x86cpu, fmpm_cpuids);
  777. static int __init fru_mem_poison_init(void)
  778. {
  779. int ret;
  780. if (!x86_match_cpu(fmpm_cpuids)) {
  781. ret = -ENODEV;
  782. goto out;
  783. }
  784. if (erst_disable) {
  785. pr_debug("ERST not available\n");
  786. ret = -ENODEV;
  787. goto out;
  788. }
  789. ret = get_system_info();
  790. if (ret)
  791. goto out;
  792. ret = allocate_records();
  793. if (ret)
  794. goto out;
  795. ret = init_fmps();
  796. if (ret)
  797. goto out_free;
  798. ret = get_saved_records();
  799. if (ret)
  800. goto out_free;
  801. ret = save_new_records();
  802. if (ret)
  803. goto out_free;
  804. setup_debugfs();
  805. retire_mem_records();
  806. mce_register_decode_chain(&fru_mem_poison_nb);
  807. pr_info("FRU Memory Poison Manager initialized\n");
  808. return 0;
  809. out_free:
  810. free_records();
  811. out:
  812. return ret;
  813. }
  814. static void __exit fru_mem_poison_exit(void)
  815. {
  816. mce_unregister_decode_chain(&fru_mem_poison_nb);
  817. debugfs_remove(fmpm_dfs_dir);
  818. free_records();
  819. }
  820. module_init(fru_mem_poison_init);
  821. module_exit(fru_mem_poison_exit);
  822. MODULE_LICENSE("GPL");
  823. MODULE_DESCRIPTION("FRU Memory Poison Manager");