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