apei-base.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /*
  2. * apei-base.c - ACPI Platform Error Interface (APEI) supporting
  3. * infrastructure
  4. *
  5. * APEI allows to report errors (for example from the chipset) to the
  6. * the operating system. This improves NMI handling especially. In
  7. * addition it supports error serialization and error injection.
  8. *
  9. * For more information about APEI, please refer to ACPI Specification
  10. * version 4.0, chapter 17.
  11. *
  12. * This file has Common functions used by more than one APEI table,
  13. * including framework of interpreter for ERST and EINJ; resource
  14. * management for APEI registers.
  15. *
  16. * Copyright (C) 2009, Intel Corp.
  17. * Author: Huang Ying <ying.huang@intel.com>
  18. *
  19. * This program is free software; you can redistribute it and/or
  20. * modify it under the terms of the GNU General Public License version
  21. * 2 as published by the Free Software Foundation.
  22. *
  23. * This program is distributed in the hope that it will be useful,
  24. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  26. * GNU General Public License for more details.
  27. */
  28. #include <linux/kernel.h>
  29. #include <linux/module.h>
  30. #include <linux/init.h>
  31. #include <linux/acpi.h>
  32. #include <linux/slab.h>
  33. #include <linux/io.h>
  34. #include <linux/kref.h>
  35. #include <linux/rculist.h>
  36. #include <linux/interrupt.h>
  37. #include <linux/debugfs.h>
  38. #include <asm/unaligned.h>
  39. #include "apei-internal.h"
  40. #define APEI_PFX "APEI: "
  41. /*
  42. * APEI ERST (Error Record Serialization Table) and EINJ (Error
  43. * INJection) interpreter framework.
  44. */
  45. #define APEI_EXEC_PRESERVE_REGISTER 0x1
  46. void apei_exec_ctx_init(struct apei_exec_context *ctx,
  47. struct apei_exec_ins_type *ins_table,
  48. u32 instructions,
  49. struct acpi_whea_header *action_table,
  50. u32 entries)
  51. {
  52. ctx->ins_table = ins_table;
  53. ctx->instructions = instructions;
  54. ctx->action_table = action_table;
  55. ctx->entries = entries;
  56. }
  57. EXPORT_SYMBOL_GPL(apei_exec_ctx_init);
  58. int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val)
  59. {
  60. int rc;
  61. rc = apei_read(val, &entry->register_region);
  62. if (rc)
  63. return rc;
  64. *val >>= entry->register_region.bit_offset;
  65. *val &= entry->mask;
  66. return 0;
  67. }
  68. int apei_exec_read_register(struct apei_exec_context *ctx,
  69. struct acpi_whea_header *entry)
  70. {
  71. int rc;
  72. u64 val = 0;
  73. rc = __apei_exec_read_register(entry, &val);
  74. if (rc)
  75. return rc;
  76. ctx->value = val;
  77. return 0;
  78. }
  79. EXPORT_SYMBOL_GPL(apei_exec_read_register);
  80. int apei_exec_read_register_value(struct apei_exec_context *ctx,
  81. struct acpi_whea_header *entry)
  82. {
  83. int rc;
  84. rc = apei_exec_read_register(ctx, entry);
  85. if (rc)
  86. return rc;
  87. ctx->value = (ctx->value == entry->value);
  88. return 0;
  89. }
  90. EXPORT_SYMBOL_GPL(apei_exec_read_register_value);
  91. int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val)
  92. {
  93. int rc;
  94. val &= entry->mask;
  95. val <<= entry->register_region.bit_offset;
  96. if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) {
  97. u64 valr = 0;
  98. rc = apei_read(&valr, &entry->register_region);
  99. if (rc)
  100. return rc;
  101. valr &= ~(entry->mask << entry->register_region.bit_offset);
  102. val |= valr;
  103. }
  104. rc = apei_write(val, &entry->register_region);
  105. return rc;
  106. }
  107. int apei_exec_write_register(struct apei_exec_context *ctx,
  108. struct acpi_whea_header *entry)
  109. {
  110. return __apei_exec_write_register(entry, ctx->value);
  111. }
  112. EXPORT_SYMBOL_GPL(apei_exec_write_register);
  113. int apei_exec_write_register_value(struct apei_exec_context *ctx,
  114. struct acpi_whea_header *entry)
  115. {
  116. int rc;
  117. ctx->value = entry->value;
  118. rc = apei_exec_write_register(ctx, entry);
  119. return rc;
  120. }
  121. EXPORT_SYMBOL_GPL(apei_exec_write_register_value);
  122. int apei_exec_noop(struct apei_exec_context *ctx,
  123. struct acpi_whea_header *entry)
  124. {
  125. return 0;
  126. }
  127. EXPORT_SYMBOL_GPL(apei_exec_noop);
  128. /*
  129. * Interpret the specified action. Go through whole action table,
  130. * execute all instructions belong to the action.
  131. */
  132. int __apei_exec_run(struct apei_exec_context *ctx, u8 action,
  133. bool optional)
  134. {
  135. int rc = -ENOENT;
  136. u32 i, ip;
  137. struct acpi_whea_header *entry;
  138. apei_exec_ins_func_t run;
  139. ctx->ip = 0;
  140. /*
  141. * "ip" is the instruction pointer of current instruction,
  142. * "ctx->ip" specifies the next instruction to executed,
  143. * instruction "run" function may change the "ctx->ip" to
  144. * implement "goto" semantics.
  145. */
  146. rewind:
  147. ip = 0;
  148. for (i = 0; i < ctx->entries; i++) {
  149. entry = &ctx->action_table[i];
  150. if (entry->action != action)
  151. continue;
  152. if (ip == ctx->ip) {
  153. if (entry->instruction >= ctx->instructions ||
  154. !ctx->ins_table[entry->instruction].run) {
  155. pr_warning(FW_WARN APEI_PFX
  156. "Invalid action table, unknown instruction type: %d\n",
  157. entry->instruction);
  158. return -EINVAL;
  159. }
  160. run = ctx->ins_table[entry->instruction].run;
  161. rc = run(ctx, entry);
  162. if (rc < 0)
  163. return rc;
  164. else if (rc != APEI_EXEC_SET_IP)
  165. ctx->ip++;
  166. }
  167. ip++;
  168. if (ctx->ip < ip)
  169. goto rewind;
  170. }
  171. return !optional && rc < 0 ? rc : 0;
  172. }
  173. EXPORT_SYMBOL_GPL(__apei_exec_run);
  174. typedef int (*apei_exec_entry_func_t)(struct apei_exec_context *ctx,
  175. struct acpi_whea_header *entry,
  176. void *data);
  177. static int apei_exec_for_each_entry(struct apei_exec_context *ctx,
  178. apei_exec_entry_func_t func,
  179. void *data,
  180. int *end)
  181. {
  182. u8 ins;
  183. int i, rc;
  184. struct acpi_whea_header *entry;
  185. struct apei_exec_ins_type *ins_table = ctx->ins_table;
  186. for (i = 0; i < ctx->entries; i++) {
  187. entry = ctx->action_table + i;
  188. ins = entry->instruction;
  189. if (end)
  190. *end = i;
  191. if (ins >= ctx->instructions || !ins_table[ins].run) {
  192. pr_warning(FW_WARN APEI_PFX
  193. "Invalid action table, unknown instruction type: %d\n",
  194. ins);
  195. return -EINVAL;
  196. }
  197. rc = func(ctx, entry, data);
  198. if (rc)
  199. return rc;
  200. }
  201. return 0;
  202. }
  203. static int pre_map_gar_callback(struct apei_exec_context *ctx,
  204. struct acpi_whea_header *entry,
  205. void *data)
  206. {
  207. u8 ins = entry->instruction;
  208. if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
  209. return apei_map_generic_address(&entry->register_region);
  210. return 0;
  211. }
  212. /*
  213. * Pre-map all GARs in action table to make it possible to access them
  214. * in NMI handler.
  215. */
  216. int apei_exec_pre_map_gars(struct apei_exec_context *ctx)
  217. {
  218. int rc, end;
  219. rc = apei_exec_for_each_entry(ctx, pre_map_gar_callback,
  220. NULL, &end);
  221. if (rc) {
  222. struct apei_exec_context ctx_unmap;
  223. memcpy(&ctx_unmap, ctx, sizeof(*ctx));
  224. ctx_unmap.entries = end;
  225. apei_exec_post_unmap_gars(&ctx_unmap);
  226. }
  227. return rc;
  228. }
  229. EXPORT_SYMBOL_GPL(apei_exec_pre_map_gars);
  230. static int post_unmap_gar_callback(struct apei_exec_context *ctx,
  231. struct acpi_whea_header *entry,
  232. void *data)
  233. {
  234. u8 ins = entry->instruction;
  235. if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
  236. apei_unmap_generic_address(&entry->register_region);
  237. return 0;
  238. }
  239. /* Post-unmap all GAR in action table. */
  240. int apei_exec_post_unmap_gars(struct apei_exec_context *ctx)
  241. {
  242. return apei_exec_for_each_entry(ctx, post_unmap_gar_callback,
  243. NULL, NULL);
  244. }
  245. EXPORT_SYMBOL_GPL(apei_exec_post_unmap_gars);
  246. /*
  247. * Resource management for GARs in APEI
  248. */
  249. struct apei_res {
  250. struct list_head list;
  251. unsigned long start;
  252. unsigned long end;
  253. };
  254. /* Collect all resources requested, to avoid conflict */
  255. struct apei_resources apei_resources_all = {
  256. .iomem = LIST_HEAD_INIT(apei_resources_all.iomem),
  257. .ioport = LIST_HEAD_INIT(apei_resources_all.ioport),
  258. };
  259. static int apei_res_add(struct list_head *res_list,
  260. unsigned long start, unsigned long size)
  261. {
  262. struct apei_res *res, *resn, *res_ins = NULL;
  263. unsigned long end = start + size;
  264. if (end <= start)
  265. return 0;
  266. repeat:
  267. list_for_each_entry_safe(res, resn, res_list, list) {
  268. if (res->start > end || res->end < start)
  269. continue;
  270. else if (end <= res->end && start >= res->start) {
  271. kfree(res_ins);
  272. return 0;
  273. }
  274. list_del(&res->list);
  275. res->start = start = min(res->start, start);
  276. res->end = end = max(res->end, end);
  277. kfree(res_ins);
  278. res_ins = res;
  279. goto repeat;
  280. }
  281. if (res_ins)
  282. list_add(&res_ins->list, res_list);
  283. else {
  284. res_ins = kmalloc(sizeof(*res), GFP_KERNEL);
  285. if (!res_ins)
  286. return -ENOMEM;
  287. res_ins->start = start;
  288. res_ins->end = end;
  289. list_add(&res_ins->list, res_list);
  290. }
  291. return 0;
  292. }
  293. static int apei_res_sub(struct list_head *res_list1,
  294. struct list_head *res_list2)
  295. {
  296. struct apei_res *res1, *resn1, *res2, *res;
  297. res1 = list_entry(res_list1->next, struct apei_res, list);
  298. resn1 = list_entry(res1->list.next, struct apei_res, list);
  299. while (&res1->list != res_list1) {
  300. list_for_each_entry(res2, res_list2, list) {
  301. if (res1->start >= res2->end ||
  302. res1->end <= res2->start)
  303. continue;
  304. else if (res1->end <= res2->end &&
  305. res1->start >= res2->start) {
  306. list_del(&res1->list);
  307. kfree(res1);
  308. break;
  309. } else if (res1->end > res2->end &&
  310. res1->start < res2->start) {
  311. res = kmalloc(sizeof(*res), GFP_KERNEL);
  312. if (!res)
  313. return -ENOMEM;
  314. res->start = res2->end;
  315. res->end = res1->end;
  316. res1->end = res2->start;
  317. list_add(&res->list, &res1->list);
  318. resn1 = res;
  319. } else {
  320. if (res1->start < res2->start)
  321. res1->end = res2->start;
  322. else
  323. res1->start = res2->end;
  324. }
  325. }
  326. res1 = resn1;
  327. resn1 = list_entry(resn1->list.next, struct apei_res, list);
  328. }
  329. return 0;
  330. }
  331. static void apei_res_clean(struct list_head *res_list)
  332. {
  333. struct apei_res *res, *resn;
  334. list_for_each_entry_safe(res, resn, res_list, list) {
  335. list_del(&res->list);
  336. kfree(res);
  337. }
  338. }
  339. void apei_resources_fini(struct apei_resources *resources)
  340. {
  341. apei_res_clean(&resources->iomem);
  342. apei_res_clean(&resources->ioport);
  343. }
  344. EXPORT_SYMBOL_GPL(apei_resources_fini);
  345. static int apei_resources_merge(struct apei_resources *resources1,
  346. struct apei_resources *resources2)
  347. {
  348. int rc;
  349. struct apei_res *res;
  350. list_for_each_entry(res, &resources2->iomem, list) {
  351. rc = apei_res_add(&resources1->iomem, res->start,
  352. res->end - res->start);
  353. if (rc)
  354. return rc;
  355. }
  356. list_for_each_entry(res, &resources2->ioport, list) {
  357. rc = apei_res_add(&resources1->ioport, res->start,
  358. res->end - res->start);
  359. if (rc)
  360. return rc;
  361. }
  362. return 0;
  363. }
  364. int apei_resources_add(struct apei_resources *resources,
  365. unsigned long start, unsigned long size,
  366. bool iomem)
  367. {
  368. if (iomem)
  369. return apei_res_add(&resources->iomem, start, size);
  370. else
  371. return apei_res_add(&resources->ioport, start, size);
  372. }
  373. EXPORT_SYMBOL_GPL(apei_resources_add);
  374. /*
  375. * EINJ has two groups of GARs (EINJ table entry and trigger table
  376. * entry), so common resources are subtracted from the trigger table
  377. * resources before the second requesting.
  378. */
  379. int apei_resources_sub(struct apei_resources *resources1,
  380. struct apei_resources *resources2)
  381. {
  382. int rc;
  383. rc = apei_res_sub(&resources1->iomem, &resources2->iomem);
  384. if (rc)
  385. return rc;
  386. return apei_res_sub(&resources1->ioport, &resources2->ioport);
  387. }
  388. EXPORT_SYMBOL_GPL(apei_resources_sub);
  389. static int apei_get_res_callback(__u64 start, __u64 size, void *data)
  390. {
  391. struct apei_resources *resources = data;
  392. return apei_res_add(&resources->iomem, start, size);
  393. }
  394. static int apei_get_nvs_resources(struct apei_resources *resources)
  395. {
  396. return acpi_nvs_for_each_region(apei_get_res_callback, resources);
  397. }
  398. int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size,
  399. void *data), void *data);
  400. static int apei_get_arch_resources(struct apei_resources *resources)
  401. {
  402. return arch_apei_filter_addr(apei_get_res_callback, resources);
  403. }
  404. /*
  405. * IO memory/port resource management mechanism is used to check
  406. * whether memory/port area used by GARs conflicts with normal memory
  407. * or IO memory/port of devices.
  408. */
  409. int apei_resources_request(struct apei_resources *resources,
  410. const char *desc)
  411. {
  412. struct apei_res *res, *res_bak = NULL;
  413. struct resource *r;
  414. struct apei_resources nvs_resources, arch_res;
  415. int rc;
  416. rc = apei_resources_sub(resources, &apei_resources_all);
  417. if (rc)
  418. return rc;
  419. /*
  420. * Some firmware uses ACPI NVS region, that has been marked as
  421. * busy, so exclude it from APEI resources to avoid false
  422. * conflict.
  423. */
  424. apei_resources_init(&nvs_resources);
  425. rc = apei_get_nvs_resources(&nvs_resources);
  426. if (rc)
  427. goto nvs_res_fini;
  428. rc = apei_resources_sub(resources, &nvs_resources);
  429. if (rc)
  430. goto nvs_res_fini;
  431. if (arch_apei_filter_addr) {
  432. apei_resources_init(&arch_res);
  433. rc = apei_get_arch_resources(&arch_res);
  434. if (rc)
  435. goto arch_res_fini;
  436. rc = apei_resources_sub(resources, &arch_res);
  437. if (rc)
  438. goto arch_res_fini;
  439. }
  440. rc = -EINVAL;
  441. list_for_each_entry(res, &resources->iomem, list) {
  442. r = request_mem_region(res->start, res->end - res->start,
  443. desc);
  444. if (!r) {
  445. pr_err(APEI_PFX
  446. "Can not request [mem %#010llx-%#010llx] for %s registers\n",
  447. (unsigned long long)res->start,
  448. (unsigned long long)res->end - 1, desc);
  449. res_bak = res;
  450. goto err_unmap_iomem;
  451. }
  452. }
  453. list_for_each_entry(res, &resources->ioport, list) {
  454. r = request_region(res->start, res->end - res->start, desc);
  455. if (!r) {
  456. pr_err(APEI_PFX
  457. "Can not request [io %#06llx-%#06llx] for %s registers\n",
  458. (unsigned long long)res->start,
  459. (unsigned long long)res->end - 1, desc);
  460. res_bak = res;
  461. goto err_unmap_ioport;
  462. }
  463. }
  464. rc = apei_resources_merge(&apei_resources_all, resources);
  465. if (rc) {
  466. pr_err(APEI_PFX "Fail to merge resources!\n");
  467. goto err_unmap_ioport;
  468. }
  469. return 0;
  470. err_unmap_ioport:
  471. list_for_each_entry(res, &resources->ioport, list) {
  472. if (res == res_bak)
  473. break;
  474. release_region(res->start, res->end - res->start);
  475. }
  476. res_bak = NULL;
  477. err_unmap_iomem:
  478. list_for_each_entry(res, &resources->iomem, list) {
  479. if (res == res_bak)
  480. break;
  481. release_mem_region(res->start, res->end - res->start);
  482. }
  483. arch_res_fini:
  484. apei_resources_fini(&arch_res);
  485. nvs_res_fini:
  486. apei_resources_fini(&nvs_resources);
  487. return rc;
  488. }
  489. EXPORT_SYMBOL_GPL(apei_resources_request);
  490. void apei_resources_release(struct apei_resources *resources)
  491. {
  492. int rc;
  493. struct apei_res *res;
  494. list_for_each_entry(res, &resources->iomem, list)
  495. release_mem_region(res->start, res->end - res->start);
  496. list_for_each_entry(res, &resources->ioport, list)
  497. release_region(res->start, res->end - res->start);
  498. rc = apei_resources_sub(&apei_resources_all, resources);
  499. if (rc)
  500. pr_err(APEI_PFX "Fail to sub resources!\n");
  501. }
  502. EXPORT_SYMBOL_GPL(apei_resources_release);
  503. static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr,
  504. u32 *access_bit_width)
  505. {
  506. u32 bit_width, bit_offset, access_size_code, space_id;
  507. bit_width = reg->bit_width;
  508. bit_offset = reg->bit_offset;
  509. access_size_code = reg->access_width;
  510. space_id = reg->space_id;
  511. *paddr = get_unaligned(&reg->address);
  512. if (!*paddr) {
  513. pr_warning(FW_BUG APEI_PFX
  514. "Invalid physical address in GAR [0x%llx/%u/%u/%u/%u]\n",
  515. *paddr, bit_width, bit_offset, access_size_code,
  516. space_id);
  517. return -EINVAL;
  518. }
  519. if (access_size_code < 1 || access_size_code > 4) {
  520. pr_warning(FW_BUG APEI_PFX
  521. "Invalid access size code in GAR [0x%llx/%u/%u/%u/%u]\n",
  522. *paddr, bit_width, bit_offset, access_size_code,
  523. space_id);
  524. return -EINVAL;
  525. }
  526. *access_bit_width = 1UL << (access_size_code + 2);
  527. /* Fixup common BIOS bug */
  528. if (bit_width == 32 && bit_offset == 0 && (*paddr & 0x03) == 0 &&
  529. *access_bit_width < 32)
  530. *access_bit_width = 32;
  531. else if (bit_width == 64 && bit_offset == 0 && (*paddr & 0x07) == 0 &&
  532. *access_bit_width < 64)
  533. *access_bit_width = 64;
  534. if ((bit_width + bit_offset) > *access_bit_width) {
  535. pr_warning(FW_BUG APEI_PFX
  536. "Invalid bit width + offset in GAR [0x%llx/%u/%u/%u/%u]\n",
  537. *paddr, bit_width, bit_offset, access_size_code,
  538. space_id);
  539. return -EINVAL;
  540. }
  541. if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY &&
  542. space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
  543. pr_warning(FW_BUG APEI_PFX
  544. "Invalid address space type in GAR [0x%llx/%u/%u/%u/%u]\n",
  545. *paddr, bit_width, bit_offset, access_size_code,
  546. space_id);
  547. return -EINVAL;
  548. }
  549. return 0;
  550. }
  551. int apei_map_generic_address(struct acpi_generic_address *reg)
  552. {
  553. int rc;
  554. u32 access_bit_width;
  555. u64 address;
  556. rc = apei_check_gar(reg, &address, &access_bit_width);
  557. if (rc)
  558. return rc;
  559. return acpi_os_map_generic_address(reg);
  560. }
  561. EXPORT_SYMBOL_GPL(apei_map_generic_address);
  562. /* read GAR in interrupt (including NMI) or process context */
  563. int apei_read(u64 *val, struct acpi_generic_address *reg)
  564. {
  565. int rc;
  566. u32 access_bit_width;
  567. u64 address;
  568. acpi_status status;
  569. rc = apei_check_gar(reg, &address, &access_bit_width);
  570. if (rc)
  571. return rc;
  572. *val = 0;
  573. switch(reg->space_id) {
  574. case ACPI_ADR_SPACE_SYSTEM_MEMORY:
  575. status = acpi_os_read_memory((acpi_physical_address) address,
  576. val, access_bit_width);
  577. if (ACPI_FAILURE(status))
  578. return -EIO;
  579. break;
  580. case ACPI_ADR_SPACE_SYSTEM_IO:
  581. status = acpi_os_read_port(address, (u32 *)val,
  582. access_bit_width);
  583. if (ACPI_FAILURE(status))
  584. return -EIO;
  585. break;
  586. default:
  587. return -EINVAL;
  588. }
  589. return 0;
  590. }
  591. EXPORT_SYMBOL_GPL(apei_read);
  592. /* write GAR in interrupt (including NMI) or process context */
  593. int apei_write(u64 val, struct acpi_generic_address *reg)
  594. {
  595. int rc;
  596. u32 access_bit_width;
  597. u64 address;
  598. acpi_status status;
  599. rc = apei_check_gar(reg, &address, &access_bit_width);
  600. if (rc)
  601. return rc;
  602. switch (reg->space_id) {
  603. case ACPI_ADR_SPACE_SYSTEM_MEMORY:
  604. status = acpi_os_write_memory((acpi_physical_address) address,
  605. val, access_bit_width);
  606. if (ACPI_FAILURE(status))
  607. return -EIO;
  608. break;
  609. case ACPI_ADR_SPACE_SYSTEM_IO:
  610. status = acpi_os_write_port(address, val, access_bit_width);
  611. if (ACPI_FAILURE(status))
  612. return -EIO;
  613. break;
  614. default:
  615. return -EINVAL;
  616. }
  617. return 0;
  618. }
  619. EXPORT_SYMBOL_GPL(apei_write);
  620. static int collect_res_callback(struct apei_exec_context *ctx,
  621. struct acpi_whea_header *entry,
  622. void *data)
  623. {
  624. struct apei_resources *resources = data;
  625. struct acpi_generic_address *reg = &entry->register_region;
  626. u8 ins = entry->instruction;
  627. u32 access_bit_width;
  628. u64 paddr;
  629. int rc;
  630. if (!(ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER))
  631. return 0;
  632. rc = apei_check_gar(reg, &paddr, &access_bit_width);
  633. if (rc)
  634. return rc;
  635. switch (reg->space_id) {
  636. case ACPI_ADR_SPACE_SYSTEM_MEMORY:
  637. return apei_res_add(&resources->iomem, paddr,
  638. access_bit_width / 8);
  639. case ACPI_ADR_SPACE_SYSTEM_IO:
  640. return apei_res_add(&resources->ioport, paddr,
  641. access_bit_width / 8);
  642. default:
  643. return -EINVAL;
  644. }
  645. }
  646. /*
  647. * Same register may be used by multiple instructions in GARs, so
  648. * resources are collected before requesting.
  649. */
  650. int apei_exec_collect_resources(struct apei_exec_context *ctx,
  651. struct apei_resources *resources)
  652. {
  653. return apei_exec_for_each_entry(ctx, collect_res_callback,
  654. resources, NULL);
  655. }
  656. EXPORT_SYMBOL_GPL(apei_exec_collect_resources);
  657. struct dentry *apei_get_debugfs_dir(void)
  658. {
  659. static struct dentry *dapei;
  660. if (!dapei)
  661. dapei = debugfs_create_dir("apei", NULL);
  662. return dapei;
  663. }
  664. EXPORT_SYMBOL_GPL(apei_get_debugfs_dir);
  665. int __weak arch_apei_enable_cmcff(struct acpi_hest_header *hest_hdr,
  666. void *data)
  667. {
  668. return 1;
  669. }
  670. EXPORT_SYMBOL_GPL(arch_apei_enable_cmcff);
  671. void __weak arch_apei_report_mem_error(int sev,
  672. struct cper_sec_mem_err *mem_err)
  673. {
  674. }
  675. EXPORT_SYMBOL_GPL(arch_apei_report_mem_error);
  676. int apei_osc_setup(void)
  677. {
  678. static u8 whea_uuid_str[] = "ed855e0c-6c90-47bf-a62a-26de0fc5ad5c";
  679. acpi_handle handle;
  680. u32 capbuf[3];
  681. struct acpi_osc_context context = {
  682. .uuid_str = whea_uuid_str,
  683. .rev = 1,
  684. .cap.length = sizeof(capbuf),
  685. .cap.pointer = capbuf,
  686. };
  687. capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE;
  688. capbuf[OSC_SUPPORT_DWORD] = 1;
  689. capbuf[OSC_CONTROL_DWORD] = 0;
  690. if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))
  691. || ACPI_FAILURE(acpi_run_osc(handle, &context)))
  692. return -EIO;
  693. else {
  694. kfree(context.ret.pointer);
  695. return 0;
  696. }
  697. }
  698. EXPORT_SYMBOL_GPL(apei_osc_setup);