erst.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. /*
  2. * APEI Error Record Serialization Table support
  3. *
  4. * ERST is a way provided by APEI to save and retrieve hardware error
  5. * infomation to and from a persistent store.
  6. *
  7. * For more information about ERST, please refer to ACPI Specification
  8. * version 4.0, section 17.4.
  9. *
  10. * Copyright 2010 Intel Corp.
  11. * Author: Huang Ying <ying.huang@intel.com>
  12. *
  13. * This program is free software; you can redistribute it and/or
  14. * modify it under the terms of the GNU General Public License version
  15. * 2 as published by the Free Software Foundation.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, write to the Free Software
  24. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  25. */
  26. #include <linux/kernel.h>
  27. #include <linux/module.h>
  28. #include <linux/init.h>
  29. #include <linux/delay.h>
  30. #include <linux/io.h>
  31. #include <linux/acpi.h>
  32. #include <linux/uaccess.h>
  33. #include <linux/cper.h>
  34. #include <linux/nmi.h>
  35. #include <acpi/apei.h>
  36. #include "apei-internal.h"
  37. #define ERST_PFX "ERST: "
  38. /* ERST command status */
  39. #define ERST_STATUS_SUCCESS 0x0
  40. #define ERST_STATUS_NOT_ENOUGH_SPACE 0x1
  41. #define ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x2
  42. #define ERST_STATUS_FAILED 0x3
  43. #define ERST_STATUS_RECORD_STORE_EMPTY 0x4
  44. #define ERST_STATUS_RECORD_NOT_FOUND 0x5
  45. #define ERST_TAB_ENTRY(tab) \
  46. ((struct acpi_whea_header *)((char *)(tab) + \
  47. sizeof(struct acpi_table_erst)))
  48. #define SPIN_UNIT 100 /* 100ns */
  49. /* Firmware should respond within 1 miliseconds */
  50. #define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC)
  51. #define FIRMWARE_MAX_STALL 50 /* 50us */
  52. int erst_disable;
  53. EXPORT_SYMBOL_GPL(erst_disable);
  54. static struct acpi_table_erst *erst_tab;
  55. /* ERST Error Log Address Range atrributes */
  56. #define ERST_RANGE_RESERVED 0x0001
  57. #define ERST_RANGE_NVRAM 0x0002
  58. #define ERST_RANGE_SLOW 0x0004
  59. /*
  60. * ERST Error Log Address Range, used as buffer for reading/writing
  61. * error records.
  62. */
  63. static struct erst_erange {
  64. u64 base;
  65. u64 size;
  66. void __iomem *vaddr;
  67. u32 attr;
  68. } erst_erange;
  69. /*
  70. * Prevent ERST interpreter to run simultaneously, because the
  71. * corresponding firmware implementation may not work properly when
  72. * invoked simultaneously.
  73. *
  74. * It is used to provide exclusive accessing for ERST Error Log
  75. * Address Range too.
  76. */
  77. static DEFINE_SPINLOCK(erst_lock);
  78. static inline int erst_errno(int command_status)
  79. {
  80. switch (command_status) {
  81. case ERST_STATUS_SUCCESS:
  82. return 0;
  83. case ERST_STATUS_HARDWARE_NOT_AVAILABLE:
  84. return -ENODEV;
  85. case ERST_STATUS_NOT_ENOUGH_SPACE:
  86. return -ENOSPC;
  87. case ERST_STATUS_RECORD_STORE_EMPTY:
  88. case ERST_STATUS_RECORD_NOT_FOUND:
  89. return -ENOENT;
  90. default:
  91. return -EINVAL;
  92. }
  93. }
  94. static int erst_timedout(u64 *t, u64 spin_unit)
  95. {
  96. if ((s64)*t < spin_unit) {
  97. pr_warning(FW_WARN ERST_PFX
  98. "Firmware does not respond in time\n");
  99. return 1;
  100. }
  101. *t -= spin_unit;
  102. ndelay(spin_unit);
  103. touch_nmi_watchdog();
  104. return 0;
  105. }
  106. static int erst_exec_load_var1(struct apei_exec_context *ctx,
  107. struct acpi_whea_header *entry)
  108. {
  109. return __apei_exec_read_register(entry, &ctx->var1);
  110. }
  111. static int erst_exec_load_var2(struct apei_exec_context *ctx,
  112. struct acpi_whea_header *entry)
  113. {
  114. return __apei_exec_read_register(entry, &ctx->var2);
  115. }
  116. static int erst_exec_store_var1(struct apei_exec_context *ctx,
  117. struct acpi_whea_header *entry)
  118. {
  119. return __apei_exec_write_register(entry, ctx->var1);
  120. }
  121. static int erst_exec_add(struct apei_exec_context *ctx,
  122. struct acpi_whea_header *entry)
  123. {
  124. ctx->var1 += ctx->var2;
  125. return 0;
  126. }
  127. static int erst_exec_subtract(struct apei_exec_context *ctx,
  128. struct acpi_whea_header *entry)
  129. {
  130. ctx->var1 -= ctx->var2;
  131. return 0;
  132. }
  133. static int erst_exec_add_value(struct apei_exec_context *ctx,
  134. struct acpi_whea_header *entry)
  135. {
  136. int rc;
  137. u64 val;
  138. rc = __apei_exec_read_register(entry, &val);
  139. if (rc)
  140. return rc;
  141. val += ctx->value;
  142. rc = __apei_exec_write_register(entry, val);
  143. return rc;
  144. }
  145. static int erst_exec_subtract_value(struct apei_exec_context *ctx,
  146. struct acpi_whea_header *entry)
  147. {
  148. int rc;
  149. u64 val;
  150. rc = __apei_exec_read_register(entry, &val);
  151. if (rc)
  152. return rc;
  153. val -= ctx->value;
  154. rc = __apei_exec_write_register(entry, val);
  155. return rc;
  156. }
  157. static int erst_exec_stall(struct apei_exec_context *ctx,
  158. struct acpi_whea_header *entry)
  159. {
  160. u64 stall_time;
  161. if (ctx->value > FIRMWARE_MAX_STALL) {
  162. if (!in_nmi())
  163. pr_warning(FW_WARN ERST_PFX
  164. "Too long stall time for stall instruction: %llx.\n",
  165. ctx->value);
  166. stall_time = FIRMWARE_MAX_STALL;
  167. } else
  168. stall_time = ctx->value;
  169. udelay(stall_time);
  170. return 0;
  171. }
  172. static int erst_exec_stall_while_true(struct apei_exec_context *ctx,
  173. struct acpi_whea_header *entry)
  174. {
  175. int rc;
  176. u64 val;
  177. u64 timeout = FIRMWARE_TIMEOUT;
  178. u64 stall_time;
  179. if (ctx->var1 > FIRMWARE_MAX_STALL) {
  180. if (!in_nmi())
  181. pr_warning(FW_WARN ERST_PFX
  182. "Too long stall time for stall while true instruction: %llx.\n",
  183. ctx->var1);
  184. stall_time = FIRMWARE_MAX_STALL;
  185. } else
  186. stall_time = ctx->var1;
  187. for (;;) {
  188. rc = __apei_exec_read_register(entry, &val);
  189. if (rc)
  190. return rc;
  191. if (val != ctx->value)
  192. break;
  193. if (erst_timedout(&timeout, stall_time * NSEC_PER_USEC))
  194. return -EIO;
  195. }
  196. return 0;
  197. }
  198. static int erst_exec_skip_next_instruction_if_true(
  199. struct apei_exec_context *ctx,
  200. struct acpi_whea_header *entry)
  201. {
  202. int rc;
  203. u64 val;
  204. rc = __apei_exec_read_register(entry, &val);
  205. if (rc)
  206. return rc;
  207. if (val == ctx->value) {
  208. ctx->ip += 2;
  209. return APEI_EXEC_SET_IP;
  210. }
  211. return 0;
  212. }
  213. static int erst_exec_goto(struct apei_exec_context *ctx,
  214. struct acpi_whea_header *entry)
  215. {
  216. ctx->ip = ctx->value;
  217. return APEI_EXEC_SET_IP;
  218. }
  219. static int erst_exec_set_src_address_base(struct apei_exec_context *ctx,
  220. struct acpi_whea_header *entry)
  221. {
  222. return __apei_exec_read_register(entry, &ctx->src_base);
  223. }
  224. static int erst_exec_set_dst_address_base(struct apei_exec_context *ctx,
  225. struct acpi_whea_header *entry)
  226. {
  227. return __apei_exec_read_register(entry, &ctx->dst_base);
  228. }
  229. static int erst_exec_move_data(struct apei_exec_context *ctx,
  230. struct acpi_whea_header *entry)
  231. {
  232. int rc;
  233. u64 offset;
  234. rc = __apei_exec_read_register(entry, &offset);
  235. if (rc)
  236. return rc;
  237. memmove((void *)ctx->dst_base + offset,
  238. (void *)ctx->src_base + offset,
  239. ctx->var2);
  240. return 0;
  241. }
  242. static struct apei_exec_ins_type erst_ins_type[] = {
  243. [ACPI_ERST_READ_REGISTER] = {
  244. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  245. .run = apei_exec_read_register,
  246. },
  247. [ACPI_ERST_READ_REGISTER_VALUE] = {
  248. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  249. .run = apei_exec_read_register_value,
  250. },
  251. [ACPI_ERST_WRITE_REGISTER] = {
  252. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  253. .run = apei_exec_write_register,
  254. },
  255. [ACPI_ERST_WRITE_REGISTER_VALUE] = {
  256. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  257. .run = apei_exec_write_register_value,
  258. },
  259. [ACPI_ERST_NOOP] = {
  260. .flags = 0,
  261. .run = apei_exec_noop,
  262. },
  263. [ACPI_ERST_LOAD_VAR1] = {
  264. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  265. .run = erst_exec_load_var1,
  266. },
  267. [ACPI_ERST_LOAD_VAR2] = {
  268. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  269. .run = erst_exec_load_var2,
  270. },
  271. [ACPI_ERST_STORE_VAR1] = {
  272. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  273. .run = erst_exec_store_var1,
  274. },
  275. [ACPI_ERST_ADD] = {
  276. .flags = 0,
  277. .run = erst_exec_add,
  278. },
  279. [ACPI_ERST_SUBTRACT] = {
  280. .flags = 0,
  281. .run = erst_exec_subtract,
  282. },
  283. [ACPI_ERST_ADD_VALUE] = {
  284. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  285. .run = erst_exec_add_value,
  286. },
  287. [ACPI_ERST_SUBTRACT_VALUE] = {
  288. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  289. .run = erst_exec_subtract_value,
  290. },
  291. [ACPI_ERST_STALL] = {
  292. .flags = 0,
  293. .run = erst_exec_stall,
  294. },
  295. [ACPI_ERST_STALL_WHILE_TRUE] = {
  296. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  297. .run = erst_exec_stall_while_true,
  298. },
  299. [ACPI_ERST_SKIP_NEXT_IF_TRUE] = {
  300. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  301. .run = erst_exec_skip_next_instruction_if_true,
  302. },
  303. [ACPI_ERST_GOTO] = {
  304. .flags = 0,
  305. .run = erst_exec_goto,
  306. },
  307. [ACPI_ERST_SET_SRC_ADDRESS_BASE] = {
  308. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  309. .run = erst_exec_set_src_address_base,
  310. },
  311. [ACPI_ERST_SET_DST_ADDRESS_BASE] = {
  312. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  313. .run = erst_exec_set_dst_address_base,
  314. },
  315. [ACPI_ERST_MOVE_DATA] = {
  316. .flags = APEI_EXEC_INS_ACCESS_REGISTER,
  317. .run = erst_exec_move_data,
  318. },
  319. };
  320. static inline void erst_exec_ctx_init(struct apei_exec_context *ctx)
  321. {
  322. apei_exec_ctx_init(ctx, erst_ins_type, ARRAY_SIZE(erst_ins_type),
  323. ERST_TAB_ENTRY(erst_tab), erst_tab->entries);
  324. }
  325. static int erst_get_erange(struct erst_erange *range)
  326. {
  327. struct apei_exec_context ctx;
  328. int rc;
  329. erst_exec_ctx_init(&ctx);
  330. rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_RANGE);
  331. if (rc)
  332. return rc;
  333. range->base = apei_exec_ctx_get_output(&ctx);
  334. rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_LENGTH);
  335. if (rc)
  336. return rc;
  337. range->size = apei_exec_ctx_get_output(&ctx);
  338. rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_ATTRIBUTES);
  339. if (rc)
  340. return rc;
  341. range->attr = apei_exec_ctx_get_output(&ctx);
  342. return 0;
  343. }
  344. static ssize_t __erst_get_record_count(void)
  345. {
  346. struct apei_exec_context ctx;
  347. int rc;
  348. erst_exec_ctx_init(&ctx);
  349. rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_COUNT);
  350. if (rc)
  351. return rc;
  352. return apei_exec_ctx_get_output(&ctx);
  353. }
  354. ssize_t erst_get_record_count(void)
  355. {
  356. ssize_t count;
  357. unsigned long flags;
  358. if (erst_disable)
  359. return -ENODEV;
  360. spin_lock_irqsave(&erst_lock, flags);
  361. count = __erst_get_record_count();
  362. spin_unlock_irqrestore(&erst_lock, flags);
  363. return count;
  364. }
  365. EXPORT_SYMBOL_GPL(erst_get_record_count);
  366. static int __erst_get_next_record_id(u64 *record_id)
  367. {
  368. struct apei_exec_context ctx;
  369. int rc;
  370. erst_exec_ctx_init(&ctx);
  371. rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_ID);
  372. if (rc)
  373. return rc;
  374. *record_id = apei_exec_ctx_get_output(&ctx);
  375. return 0;
  376. }
  377. /*
  378. * Get the record ID of an existing error record on the persistent
  379. * storage. If there is no error record on the persistent storage, the
  380. * returned record_id is APEI_ERST_INVALID_RECORD_ID.
  381. */
  382. int erst_get_next_record_id(u64 *record_id)
  383. {
  384. int rc;
  385. unsigned long flags;
  386. if (erst_disable)
  387. return -ENODEV;
  388. spin_lock_irqsave(&erst_lock, flags);
  389. rc = __erst_get_next_record_id(record_id);
  390. spin_unlock_irqrestore(&erst_lock, flags);
  391. return rc;
  392. }
  393. EXPORT_SYMBOL_GPL(erst_get_next_record_id);
  394. static int __erst_write_to_storage(u64 offset)
  395. {
  396. struct apei_exec_context ctx;
  397. u64 timeout = FIRMWARE_TIMEOUT;
  398. u64 val;
  399. int rc;
  400. erst_exec_ctx_init(&ctx);
  401. rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_WRITE);
  402. if (rc)
  403. return rc;
  404. apei_exec_ctx_set_input(&ctx, offset);
  405. rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
  406. if (rc)
  407. return rc;
  408. rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
  409. if (rc)
  410. return rc;
  411. for (;;) {
  412. rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
  413. if (rc)
  414. return rc;
  415. val = apei_exec_ctx_get_output(&ctx);
  416. if (!val)
  417. break;
  418. if (erst_timedout(&timeout, SPIN_UNIT))
  419. return -EIO;
  420. }
  421. rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
  422. if (rc)
  423. return rc;
  424. val = apei_exec_ctx_get_output(&ctx);
  425. rc = apei_exec_run(&ctx, ACPI_ERST_END);
  426. if (rc)
  427. return rc;
  428. return erst_errno(val);
  429. }
  430. static int __erst_read_from_storage(u64 record_id, u64 offset)
  431. {
  432. struct apei_exec_context ctx;
  433. u64 timeout = FIRMWARE_TIMEOUT;
  434. u64 val;
  435. int rc;
  436. erst_exec_ctx_init(&ctx);
  437. rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_READ);
  438. if (rc)
  439. return rc;
  440. apei_exec_ctx_set_input(&ctx, offset);
  441. rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
  442. if (rc)
  443. return rc;
  444. apei_exec_ctx_set_input(&ctx, record_id);
  445. rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
  446. if (rc)
  447. return rc;
  448. rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
  449. if (rc)
  450. return rc;
  451. for (;;) {
  452. rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
  453. if (rc)
  454. return rc;
  455. val = apei_exec_ctx_get_output(&ctx);
  456. if (!val)
  457. break;
  458. if (erst_timedout(&timeout, SPIN_UNIT))
  459. return -EIO;
  460. };
  461. rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
  462. if (rc)
  463. return rc;
  464. val = apei_exec_ctx_get_output(&ctx);
  465. rc = apei_exec_run(&ctx, ACPI_ERST_END);
  466. if (rc)
  467. return rc;
  468. return erst_errno(val);
  469. }
  470. static int __erst_clear_from_storage(u64 record_id)
  471. {
  472. struct apei_exec_context ctx;
  473. u64 timeout = FIRMWARE_TIMEOUT;
  474. u64 val;
  475. int rc;
  476. erst_exec_ctx_init(&ctx);
  477. rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_CLEAR);
  478. if (rc)
  479. return rc;
  480. apei_exec_ctx_set_input(&ctx, record_id);
  481. rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
  482. if (rc)
  483. return rc;
  484. rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
  485. if (rc)
  486. return rc;
  487. for (;;) {
  488. rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
  489. if (rc)
  490. return rc;
  491. val = apei_exec_ctx_get_output(&ctx);
  492. if (!val)
  493. break;
  494. if (erst_timedout(&timeout, SPIN_UNIT))
  495. return -EIO;
  496. }
  497. rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
  498. if (rc)
  499. return rc;
  500. val = apei_exec_ctx_get_output(&ctx);
  501. rc = apei_exec_run(&ctx, ACPI_ERST_END);
  502. if (rc)
  503. return rc;
  504. return erst_errno(val);
  505. }
  506. /* NVRAM ERST Error Log Address Range is not supported yet */
  507. static void pr_unimpl_nvram(void)
  508. {
  509. if (printk_ratelimit())
  510. pr_warning(ERST_PFX
  511. "NVRAM ERST Log Address Range is not implemented yet\n");
  512. }
  513. static int __erst_write_to_nvram(const struct cper_record_header *record)
  514. {
  515. /* do not print message, because printk is not safe for NMI */
  516. return -ENOSYS;
  517. }
  518. static int __erst_read_to_erange_from_nvram(u64 record_id, u64 *offset)
  519. {
  520. pr_unimpl_nvram();
  521. return -ENOSYS;
  522. }
  523. static int __erst_clear_from_nvram(u64 record_id)
  524. {
  525. pr_unimpl_nvram();
  526. return -ENOSYS;
  527. }
  528. int erst_write(const struct cper_record_header *record)
  529. {
  530. int rc;
  531. unsigned long flags;
  532. struct cper_record_header *rcd_erange;
  533. if (erst_disable)
  534. return -ENODEV;
  535. if (memcmp(record->signature, CPER_SIG_RECORD, CPER_SIG_SIZE))
  536. return -EINVAL;
  537. if (erst_erange.attr & ERST_RANGE_NVRAM) {
  538. if (!spin_trylock_irqsave(&erst_lock, flags))
  539. return -EBUSY;
  540. rc = __erst_write_to_nvram(record);
  541. spin_unlock_irqrestore(&erst_lock, flags);
  542. return rc;
  543. }
  544. if (record->record_length > erst_erange.size)
  545. return -EINVAL;
  546. if (!spin_trylock_irqsave(&erst_lock, flags))
  547. return -EBUSY;
  548. memcpy(erst_erange.vaddr, record, record->record_length);
  549. rcd_erange = erst_erange.vaddr;
  550. /* signature for serialization system */
  551. memcpy(&rcd_erange->persistence_information, "ER", 2);
  552. rc = __erst_write_to_storage(0);
  553. spin_unlock_irqrestore(&erst_lock, flags);
  554. return rc;
  555. }
  556. EXPORT_SYMBOL_GPL(erst_write);
  557. static int __erst_read_to_erange(u64 record_id, u64 *offset)
  558. {
  559. int rc;
  560. if (erst_erange.attr & ERST_RANGE_NVRAM)
  561. return __erst_read_to_erange_from_nvram(
  562. record_id, offset);
  563. rc = __erst_read_from_storage(record_id, 0);
  564. if (rc)
  565. return rc;
  566. *offset = 0;
  567. return 0;
  568. }
  569. static ssize_t __erst_read(u64 record_id, struct cper_record_header *record,
  570. size_t buflen)
  571. {
  572. int rc;
  573. u64 offset, len = 0;
  574. struct cper_record_header *rcd_tmp;
  575. rc = __erst_read_to_erange(record_id, &offset);
  576. if (rc)
  577. return rc;
  578. rcd_tmp = erst_erange.vaddr + offset;
  579. len = rcd_tmp->record_length;
  580. if (len <= buflen)
  581. memcpy(record, rcd_tmp, len);
  582. return len;
  583. }
  584. /*
  585. * If return value > buflen, the buffer size is not big enough,
  586. * else if return value < 0, something goes wrong,
  587. * else everything is OK, and return value is record length
  588. */
  589. ssize_t erst_read(u64 record_id, struct cper_record_header *record,
  590. size_t buflen)
  591. {
  592. ssize_t len;
  593. unsigned long flags;
  594. if (erst_disable)
  595. return -ENODEV;
  596. spin_lock_irqsave(&erst_lock, flags);
  597. len = __erst_read(record_id, record, buflen);
  598. spin_unlock_irqrestore(&erst_lock, flags);
  599. return len;
  600. }
  601. EXPORT_SYMBOL_GPL(erst_read);
  602. /*
  603. * If return value > buflen, the buffer size is not big enough,
  604. * else if return value = 0, there is no more record to read,
  605. * else if return value < 0, something goes wrong,
  606. * else everything is OK, and return value is record length
  607. */
  608. ssize_t erst_read_next(struct cper_record_header *record, size_t buflen)
  609. {
  610. int rc;
  611. ssize_t len;
  612. unsigned long flags;
  613. u64 record_id;
  614. if (erst_disable)
  615. return -ENODEV;
  616. spin_lock_irqsave(&erst_lock, flags);
  617. rc = __erst_get_next_record_id(&record_id);
  618. if (rc) {
  619. spin_unlock_irqrestore(&erst_lock, flags);
  620. return rc;
  621. }
  622. /* no more record */
  623. if (record_id == APEI_ERST_INVALID_RECORD_ID) {
  624. spin_unlock_irqrestore(&erst_lock, flags);
  625. return 0;
  626. }
  627. len = __erst_read(record_id, record, buflen);
  628. spin_unlock_irqrestore(&erst_lock, flags);
  629. return len;
  630. }
  631. EXPORT_SYMBOL_GPL(erst_read_next);
  632. int erst_clear(u64 record_id)
  633. {
  634. int rc;
  635. unsigned long flags;
  636. if (erst_disable)
  637. return -ENODEV;
  638. spin_lock_irqsave(&erst_lock, flags);
  639. if (erst_erange.attr & ERST_RANGE_NVRAM)
  640. rc = __erst_clear_from_nvram(record_id);
  641. else
  642. rc = __erst_clear_from_storage(record_id);
  643. spin_unlock_irqrestore(&erst_lock, flags);
  644. return rc;
  645. }
  646. EXPORT_SYMBOL_GPL(erst_clear);
  647. static int __init setup_erst_disable(char *str)
  648. {
  649. erst_disable = 1;
  650. return 0;
  651. }
  652. __setup("erst_disable", setup_erst_disable);
  653. static int erst_check_table(struct acpi_table_erst *erst_tab)
  654. {
  655. if (erst_tab->header_length != sizeof(struct acpi_table_erst))
  656. return -EINVAL;
  657. if (erst_tab->header.length < sizeof(struct acpi_table_erst))
  658. return -EINVAL;
  659. if (erst_tab->entries !=
  660. (erst_tab->header.length - sizeof(struct acpi_table_erst)) /
  661. sizeof(struct acpi_erst_entry))
  662. return -EINVAL;
  663. return 0;
  664. }
  665. static int __init erst_init(void)
  666. {
  667. int rc = 0;
  668. acpi_status status;
  669. struct apei_exec_context ctx;
  670. struct apei_resources erst_resources;
  671. struct resource *r;
  672. if (acpi_disabled)
  673. goto err;
  674. if (erst_disable) {
  675. pr_info(ERST_PFX
  676. "Error Record Serialization Table (ERST) support is disabled.\n");
  677. goto err;
  678. }
  679. status = acpi_get_table(ACPI_SIG_ERST, 0,
  680. (struct acpi_table_header **)&erst_tab);
  681. if (status == AE_NOT_FOUND) {
  682. pr_info(ERST_PFX "Table is not found!\n");
  683. goto err;
  684. } else if (ACPI_FAILURE(status)) {
  685. const char *msg = acpi_format_exception(status);
  686. pr_err(ERST_PFX "Failed to get table, %s\n", msg);
  687. rc = -EINVAL;
  688. goto err;
  689. }
  690. rc = erst_check_table(erst_tab);
  691. if (rc) {
  692. pr_err(FW_BUG ERST_PFX "ERST table is invalid\n");
  693. goto err;
  694. }
  695. apei_resources_init(&erst_resources);
  696. erst_exec_ctx_init(&ctx);
  697. rc = apei_exec_collect_resources(&ctx, &erst_resources);
  698. if (rc)
  699. goto err_fini;
  700. rc = apei_resources_request(&erst_resources, "APEI ERST");
  701. if (rc)
  702. goto err_fini;
  703. rc = apei_exec_pre_map_gars(&ctx);
  704. if (rc)
  705. goto err_release;
  706. rc = erst_get_erange(&erst_erange);
  707. if (rc) {
  708. if (rc == -ENODEV)
  709. pr_info(ERST_PFX
  710. "The corresponding hardware device or firmware implementation "
  711. "is not available.\n");
  712. else
  713. pr_err(ERST_PFX
  714. "Failed to get Error Log Address Range.\n");
  715. goto err_unmap_reg;
  716. }
  717. r = request_mem_region(erst_erange.base, erst_erange.size, "APEI ERST");
  718. if (!r) {
  719. pr_err(ERST_PFX
  720. "Can not request iomem region <0x%16llx-0x%16llx> for ERST.\n",
  721. (unsigned long long)erst_erange.base,
  722. (unsigned long long)erst_erange.base + erst_erange.size);
  723. rc = -EIO;
  724. goto err_unmap_reg;
  725. }
  726. rc = -ENOMEM;
  727. erst_erange.vaddr = ioremap_cache(erst_erange.base,
  728. erst_erange.size);
  729. if (!erst_erange.vaddr)
  730. goto err_release_erange;
  731. pr_info(ERST_PFX
  732. "Error Record Serialization Table (ERST) support is initialized.\n");
  733. return 0;
  734. err_release_erange:
  735. release_mem_region(erst_erange.base, erst_erange.size);
  736. err_unmap_reg:
  737. apei_exec_post_unmap_gars(&ctx);
  738. err_release:
  739. apei_resources_release(&erst_resources);
  740. err_fini:
  741. apei_resources_fini(&erst_resources);
  742. err:
  743. erst_disable = 1;
  744. return rc;
  745. }
  746. device_initcall(erst_init);