2 * APEI Error Record Serialization Table support
4 * ERST is a way provided by APEI to save and retrieve hardware error
5 * information to and from a persistent store.
7 * For more information about ERST, please refer to ACPI Specification
8 * version 4.0, section 17.4.
10 * Copyright 2010 Intel Corp.
11 * Author: Huang Ying <ying.huang@intel.com>
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.
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.
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
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/init.h>
30 #include <linux/delay.h>
32 #include <linux/acpi.h>
33 #include <linux/uaccess.h>
34 #include <linux/cper.h>
35 #include <linux/nmi.h>
36 #include <linux/hardirq.h>
37 #include <acpi/apei.h>
39 #include "apei-internal.h"
41 #define ERST_PFX "ERST: "
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
51 #define ERST_TAB_ENTRY(tab) \
52 ((struct acpi_whea_header *)((char *)(tab) + \
53 sizeof(struct acpi_table_erst)))
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 */
61 EXPORT_SYMBOL_GPL(erst_disable
);
63 static struct acpi_table_erst
*erst_tab
;
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
71 * ERST Error Log Address Range, used as buffer for reading/writing
74 static struct erst_erange
{
82 * Prevent ERST interpreter to run simultaneously, because the
83 * corresponding firmware implementation may not work properly when
84 * invoked simultaneously.
86 * It is used to provide exclusive accessing for ERST Error Log
89 static DEFINE_RAW_SPINLOCK(erst_lock
);
91 static inline int erst_errno(int command_status
)
93 switch (command_status
) {
94 case ERST_STATUS_SUCCESS
:
96 case ERST_STATUS_HARDWARE_NOT_AVAILABLE
:
98 case ERST_STATUS_NOT_ENOUGH_SPACE
:
100 case ERST_STATUS_RECORD_STORE_EMPTY
:
101 case ERST_STATUS_RECORD_NOT_FOUND
:
108 static int erst_timedout(u64
*t
, u64 spin_unit
)
110 if ((s64
)*t
< spin_unit
) {
111 pr_warning(FW_WARN ERST_PFX
112 "Firmware does not respond in time\n");
117 touch_nmi_watchdog();
121 static int erst_exec_load_var1(struct apei_exec_context
*ctx
,
122 struct acpi_whea_header
*entry
)
124 return __apei_exec_read_register(entry
, &ctx
->var1
);
127 static int erst_exec_load_var2(struct apei_exec_context
*ctx
,
128 struct acpi_whea_header
*entry
)
130 return __apei_exec_read_register(entry
, &ctx
->var2
);
133 static int erst_exec_store_var1(struct apei_exec_context
*ctx
,
134 struct acpi_whea_header
*entry
)
136 return __apei_exec_write_register(entry
, ctx
->var1
);
139 static int erst_exec_add(struct apei_exec_context
*ctx
,
140 struct acpi_whea_header
*entry
)
142 ctx
->var1
+= ctx
->var2
;
146 static int erst_exec_subtract(struct apei_exec_context
*ctx
,
147 struct acpi_whea_header
*entry
)
149 ctx
->var1
-= ctx
->var2
;
153 static int erst_exec_add_value(struct apei_exec_context
*ctx
,
154 struct acpi_whea_header
*entry
)
159 rc
= __apei_exec_read_register(entry
, &val
);
163 rc
= __apei_exec_write_register(entry
, val
);
167 static int erst_exec_subtract_value(struct apei_exec_context
*ctx
,
168 struct acpi_whea_header
*entry
)
173 rc
= __apei_exec_read_register(entry
, &val
);
177 rc
= __apei_exec_write_register(entry
, val
);
181 static int erst_exec_stall(struct apei_exec_context
*ctx
,
182 struct acpi_whea_header
*entry
)
186 if (ctx
->value
> FIRMWARE_MAX_STALL
) {
188 pr_warning(FW_WARN ERST_PFX
189 "Too long stall time for stall instruction: %llx.\n",
191 stall_time
= FIRMWARE_MAX_STALL
;
193 stall_time
= ctx
->value
;
198 static int erst_exec_stall_while_true(struct apei_exec_context
*ctx
,
199 struct acpi_whea_header
*entry
)
203 u64 timeout
= FIRMWARE_TIMEOUT
;
206 if (ctx
->var1
> FIRMWARE_MAX_STALL
) {
208 pr_warning(FW_WARN ERST_PFX
209 "Too long stall time for stall while true instruction: %llx.\n",
211 stall_time
= FIRMWARE_MAX_STALL
;
213 stall_time
= ctx
->var1
;
216 rc
= __apei_exec_read_register(entry
, &val
);
219 if (val
!= ctx
->value
)
221 if (erst_timedout(&timeout
, stall_time
* NSEC_PER_USEC
))
227 static int erst_exec_skip_next_instruction_if_true(
228 struct apei_exec_context
*ctx
,
229 struct acpi_whea_header
*entry
)
234 rc
= __apei_exec_read_register(entry
, &val
);
237 if (val
== ctx
->value
) {
239 return APEI_EXEC_SET_IP
;
245 static int erst_exec_goto(struct apei_exec_context
*ctx
,
246 struct acpi_whea_header
*entry
)
248 ctx
->ip
= ctx
->value
;
249 return APEI_EXEC_SET_IP
;
252 static int erst_exec_set_src_address_base(struct apei_exec_context
*ctx
,
253 struct acpi_whea_header
*entry
)
255 return __apei_exec_read_register(entry
, &ctx
->src_base
);
258 static int erst_exec_set_dst_address_base(struct apei_exec_context
*ctx
,
259 struct acpi_whea_header
*entry
)
261 return __apei_exec_read_register(entry
, &ctx
->dst_base
);
264 static int erst_exec_move_data(struct apei_exec_context
*ctx
,
265 struct acpi_whea_header
*entry
)
271 /* ioremap does not work in interrupt context */
272 if (in_interrupt()) {
274 "MOVE_DATA can not be used in interrupt context");
278 rc
= __apei_exec_read_register(entry
, &offset
);
282 src
= ioremap(ctx
->src_base
+ offset
, ctx
->var2
);
285 dst
= ioremap(ctx
->dst_base
+ offset
, ctx
->var2
);
289 memmove(dst
, src
, ctx
->var2
);
297 static struct apei_exec_ins_type erst_ins_type
[] = {
298 [ACPI_ERST_READ_REGISTER
] = {
299 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
300 .run
= apei_exec_read_register
,
302 [ACPI_ERST_READ_REGISTER_VALUE
] = {
303 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
304 .run
= apei_exec_read_register_value
,
306 [ACPI_ERST_WRITE_REGISTER
] = {
307 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
308 .run
= apei_exec_write_register
,
310 [ACPI_ERST_WRITE_REGISTER_VALUE
] = {
311 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
312 .run
= apei_exec_write_register_value
,
316 .run
= apei_exec_noop
,
318 [ACPI_ERST_LOAD_VAR1
] = {
319 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
320 .run
= erst_exec_load_var1
,
322 [ACPI_ERST_LOAD_VAR2
] = {
323 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
324 .run
= erst_exec_load_var2
,
326 [ACPI_ERST_STORE_VAR1
] = {
327 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
328 .run
= erst_exec_store_var1
,
332 .run
= erst_exec_add
,
334 [ACPI_ERST_SUBTRACT
] = {
336 .run
= erst_exec_subtract
,
338 [ACPI_ERST_ADD_VALUE
] = {
339 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
340 .run
= erst_exec_add_value
,
342 [ACPI_ERST_SUBTRACT_VALUE
] = {
343 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
344 .run
= erst_exec_subtract_value
,
346 [ACPI_ERST_STALL
] = {
348 .run
= erst_exec_stall
,
350 [ACPI_ERST_STALL_WHILE_TRUE
] = {
351 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
352 .run
= erst_exec_stall_while_true
,
354 [ACPI_ERST_SKIP_NEXT_IF_TRUE
] = {
355 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
356 .run
= erst_exec_skip_next_instruction_if_true
,
360 .run
= erst_exec_goto
,
362 [ACPI_ERST_SET_SRC_ADDRESS_BASE
] = {
363 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
364 .run
= erst_exec_set_src_address_base
,
366 [ACPI_ERST_SET_DST_ADDRESS_BASE
] = {
367 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
368 .run
= erst_exec_set_dst_address_base
,
370 [ACPI_ERST_MOVE_DATA
] = {
371 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
372 .run
= erst_exec_move_data
,
376 static inline void erst_exec_ctx_init(struct apei_exec_context
*ctx
)
378 apei_exec_ctx_init(ctx
, erst_ins_type
, ARRAY_SIZE(erst_ins_type
),
379 ERST_TAB_ENTRY(erst_tab
), erst_tab
->entries
);
382 static int erst_get_erange(struct erst_erange
*range
)
384 struct apei_exec_context ctx
;
387 erst_exec_ctx_init(&ctx
);
388 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_ERROR_RANGE
);
391 range
->base
= apei_exec_ctx_get_output(&ctx
);
392 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_ERROR_LENGTH
);
395 range
->size
= apei_exec_ctx_get_output(&ctx
);
396 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_ERROR_ATTRIBUTES
);
399 range
->attr
= apei_exec_ctx_get_output(&ctx
);
404 static ssize_t
__erst_get_record_count(void)
406 struct apei_exec_context ctx
;
409 erst_exec_ctx_init(&ctx
);
410 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_RECORD_COUNT
);
413 return apei_exec_ctx_get_output(&ctx
);
416 ssize_t
erst_get_record_count(void)
424 raw_spin_lock_irqsave(&erst_lock
, flags
);
425 count
= __erst_get_record_count();
426 raw_spin_unlock_irqrestore(&erst_lock
, flags
);
430 EXPORT_SYMBOL_GPL(erst_get_record_count
);
432 static int __erst_get_next_record_id(u64
*record_id
)
434 struct apei_exec_context ctx
;
437 erst_exec_ctx_init(&ctx
);
438 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_RECORD_ID
);
441 *record_id
= apei_exec_ctx_get_output(&ctx
);
447 * Get the record ID of an existing error record on the persistent
448 * storage. If there is no error record on the persistent storage, the
449 * returned record_id is APEI_ERST_INVALID_RECORD_ID.
451 int erst_get_next_record_id(u64
*record_id
)
459 raw_spin_lock_irqsave(&erst_lock
, flags
);
460 rc
= __erst_get_next_record_id(record_id
);
461 raw_spin_unlock_irqrestore(&erst_lock
, flags
);
465 EXPORT_SYMBOL_GPL(erst_get_next_record_id
);
467 static int __erst_write_to_storage(u64 offset
)
469 struct apei_exec_context ctx
;
470 u64 timeout
= FIRMWARE_TIMEOUT
;
474 erst_exec_ctx_init(&ctx
);
475 rc
= apei_exec_run(&ctx
, ACPI_ERST_BEGIN_WRITE
);
478 apei_exec_ctx_set_input(&ctx
, offset
);
479 rc
= apei_exec_run(&ctx
, ACPI_ERST_SET_RECORD_OFFSET
);
482 rc
= apei_exec_run(&ctx
, ACPI_ERST_EXECUTE_OPERATION
);
486 rc
= apei_exec_run(&ctx
, ACPI_ERST_CHECK_BUSY_STATUS
);
489 val
= apei_exec_ctx_get_output(&ctx
);
492 if (erst_timedout(&timeout
, SPIN_UNIT
))
495 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_COMMAND_STATUS
);
498 val
= apei_exec_ctx_get_output(&ctx
);
499 rc
= apei_exec_run(&ctx
, ACPI_ERST_END
);
503 return erst_errno(val
);
506 static int __erst_read_from_storage(u64 record_id
, u64 offset
)
508 struct apei_exec_context ctx
;
509 u64 timeout
= FIRMWARE_TIMEOUT
;
513 erst_exec_ctx_init(&ctx
);
514 rc
= apei_exec_run(&ctx
, ACPI_ERST_BEGIN_READ
);
517 apei_exec_ctx_set_input(&ctx
, offset
);
518 rc
= apei_exec_run(&ctx
, ACPI_ERST_SET_RECORD_OFFSET
);
521 apei_exec_ctx_set_input(&ctx
, record_id
);
522 rc
= apei_exec_run(&ctx
, ACPI_ERST_SET_RECORD_ID
);
525 rc
= apei_exec_run(&ctx
, ACPI_ERST_EXECUTE_OPERATION
);
529 rc
= apei_exec_run(&ctx
, ACPI_ERST_CHECK_BUSY_STATUS
);
532 val
= apei_exec_ctx_get_output(&ctx
);
535 if (erst_timedout(&timeout
, SPIN_UNIT
))
538 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_COMMAND_STATUS
);
541 val
= apei_exec_ctx_get_output(&ctx
);
542 rc
= apei_exec_run(&ctx
, ACPI_ERST_END
);
546 return erst_errno(val
);
549 static int __erst_clear_from_storage(u64 record_id
)
551 struct apei_exec_context ctx
;
552 u64 timeout
= FIRMWARE_TIMEOUT
;
556 erst_exec_ctx_init(&ctx
);
557 rc
= apei_exec_run(&ctx
, ACPI_ERST_BEGIN_CLEAR
);
560 apei_exec_ctx_set_input(&ctx
, record_id
);
561 rc
= apei_exec_run(&ctx
, ACPI_ERST_SET_RECORD_ID
);
564 rc
= apei_exec_run(&ctx
, ACPI_ERST_EXECUTE_OPERATION
);
568 rc
= apei_exec_run(&ctx
, ACPI_ERST_CHECK_BUSY_STATUS
);
571 val
= apei_exec_ctx_get_output(&ctx
);
574 if (erst_timedout(&timeout
, SPIN_UNIT
))
577 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_COMMAND_STATUS
);
580 val
= apei_exec_ctx_get_output(&ctx
);
581 rc
= apei_exec_run(&ctx
, ACPI_ERST_END
);
585 return erst_errno(val
);
588 /* NVRAM ERST Error Log Address Range is not supported yet */
589 static void pr_unimpl_nvram(void)
591 if (printk_ratelimit())
593 "NVRAM ERST Log Address Range is not implemented yet\n");
596 static int __erst_write_to_nvram(const struct cper_record_header
*record
)
598 /* do not print message, because printk is not safe for NMI */
602 static int __erst_read_to_erange_from_nvram(u64 record_id
, u64
*offset
)
608 static int __erst_clear_from_nvram(u64 record_id
)
614 int erst_write(const struct cper_record_header
*record
)
618 struct cper_record_header
*rcd_erange
;
623 if (memcmp(record
->signature
, CPER_SIG_RECORD
, CPER_SIG_SIZE
))
626 if (erst_erange
.attr
& ERST_RANGE_NVRAM
) {
627 if (!raw_spin_trylock_irqsave(&erst_lock
, flags
))
629 rc
= __erst_write_to_nvram(record
);
630 raw_spin_unlock_irqrestore(&erst_lock
, flags
);
634 if (record
->record_length
> erst_erange
.size
)
637 if (!raw_spin_trylock_irqsave(&erst_lock
, flags
))
639 memcpy(erst_erange
.vaddr
, record
, record
->record_length
);
640 rcd_erange
= erst_erange
.vaddr
;
641 /* signature for serialization system */
642 memcpy(&rcd_erange
->persistence_information
, "ER", 2);
644 rc
= __erst_write_to_storage(0);
645 raw_spin_unlock_irqrestore(&erst_lock
, flags
);
649 EXPORT_SYMBOL_GPL(erst_write
);
651 static int __erst_read_to_erange(u64 record_id
, u64
*offset
)
655 if (erst_erange
.attr
& ERST_RANGE_NVRAM
)
656 return __erst_read_to_erange_from_nvram(
659 rc
= __erst_read_from_storage(record_id
, 0);
667 static ssize_t
__erst_read(u64 record_id
, struct cper_record_header
*record
,
672 struct cper_record_header
*rcd_tmp
;
674 rc
= __erst_read_to_erange(record_id
, &offset
);
677 rcd_tmp
= erst_erange
.vaddr
+ offset
;
678 len
= rcd_tmp
->record_length
;
680 memcpy(record
, rcd_tmp
, len
);
686 * If return value > buflen, the buffer size is not big enough,
687 * else if return value < 0, something goes wrong,
688 * else everything is OK, and return value is record length
690 ssize_t
erst_read(u64 record_id
, struct cper_record_header
*record
,
699 raw_spin_lock_irqsave(&erst_lock
, flags
);
700 len
= __erst_read(record_id
, record
, buflen
);
701 raw_spin_unlock_irqrestore(&erst_lock
, flags
);
704 EXPORT_SYMBOL_GPL(erst_read
);
707 * If return value > buflen, the buffer size is not big enough,
708 * else if return value = 0, there is no more record to read,
709 * else if return value < 0, something goes wrong,
710 * else everything is OK, and return value is record length
712 ssize_t
erst_read_next(struct cper_record_header
*record
, size_t buflen
)
722 raw_spin_lock_irqsave(&erst_lock
, flags
);
723 rc
= __erst_get_next_record_id(&record_id
);
725 raw_spin_unlock_irqrestore(&erst_lock
, flags
);
729 if (record_id
== APEI_ERST_INVALID_RECORD_ID
) {
730 raw_spin_unlock_irqrestore(&erst_lock
, flags
);
734 len
= __erst_read(record_id
, record
, buflen
);
735 raw_spin_unlock_irqrestore(&erst_lock
, flags
);
739 EXPORT_SYMBOL_GPL(erst_read_next
);
741 int erst_clear(u64 record_id
)
749 raw_spin_lock_irqsave(&erst_lock
, flags
);
750 if (erst_erange
.attr
& ERST_RANGE_NVRAM
)
751 rc
= __erst_clear_from_nvram(record_id
);
753 rc
= __erst_clear_from_storage(record_id
);
754 raw_spin_unlock_irqrestore(&erst_lock
, flags
);
758 EXPORT_SYMBOL_GPL(erst_clear
);
760 static int __init
setup_erst_disable(char *str
)
766 __setup("erst_disable", setup_erst_disable
);
768 static int erst_check_table(struct acpi_table_erst
*erst_tab
)
770 if ((erst_tab
->header_length
!=
771 (sizeof(struct acpi_table_erst
) - sizeof(erst_tab
->header
)))
772 && (erst_tab
->header_length
!= sizeof(struct acpi_table_einj
)))
774 if (erst_tab
->header
.length
< sizeof(struct acpi_table_erst
))
776 if (erst_tab
->entries
!=
777 (erst_tab
->header
.length
- sizeof(struct acpi_table_erst
)) /
778 sizeof(struct acpi_erst_entry
))
784 static int __init
erst_init(void)
788 struct apei_exec_context ctx
;
789 struct apei_resources erst_resources
;
797 "Error Record Serialization Table (ERST) support is disabled.\n");
801 status
= acpi_get_table(ACPI_SIG_ERST
, 0,
802 (struct acpi_table_header
**)&erst_tab
);
803 if (status
== AE_NOT_FOUND
) {
804 pr_info(ERST_PFX
"Table is not found!\n");
806 } else if (ACPI_FAILURE(status
)) {
807 const char *msg
= acpi_format_exception(status
);
808 pr_err(ERST_PFX
"Failed to get table, %s\n", msg
);
813 rc
= erst_check_table(erst_tab
);
815 pr_err(FW_BUG ERST_PFX
"ERST table is invalid\n");
819 apei_resources_init(&erst_resources
);
820 erst_exec_ctx_init(&ctx
);
821 rc
= apei_exec_collect_resources(&ctx
, &erst_resources
);
824 rc
= apei_resources_request(&erst_resources
, "APEI ERST");
827 rc
= apei_exec_pre_map_gars(&ctx
);
830 rc
= erst_get_erange(&erst_erange
);
834 "The corresponding hardware device or firmware implementation "
835 "is not available.\n");
838 "Failed to get Error Log Address Range.\n");
842 r
= request_mem_region(erst_erange
.base
, erst_erange
.size
, "APEI ERST");
845 "Can not request iomem region <0x%16llx-0x%16llx> for ERST.\n",
846 (unsigned long long)erst_erange
.base
,
847 (unsigned long long)erst_erange
.base
+ erst_erange
.size
);
852 erst_erange
.vaddr
= ioremap_cache(erst_erange
.base
,
854 if (!erst_erange
.vaddr
)
855 goto err_release_erange
;
858 "Error Record Serialization Table (ERST) support is initialized.\n");
863 release_mem_region(erst_erange
.base
, erst_erange
.size
);
865 apei_exec_post_unmap_gars(&ctx
);
867 apei_resources_release(&erst_resources
);
869 apei_resources_fini(&erst_resources
);
875 device_initcall(erst_init
);