2 * APEI Error Record Serialization Table support
4 * ERST is a way provided by APEI to save and retrieve hardware error
5 * infomation 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 <acpi/apei.h>
38 #include "apei-internal.h"
40 #define ERST_PFX "ERST: "
42 /* ERST command status */
43 #define ERST_STATUS_SUCCESS 0x0
44 #define ERST_STATUS_NOT_ENOUGH_SPACE 0x1
45 #define ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x2
46 #define ERST_STATUS_FAILED 0x3
47 #define ERST_STATUS_RECORD_STORE_EMPTY 0x4
48 #define ERST_STATUS_RECORD_NOT_FOUND 0x5
50 #define ERST_TAB_ENTRY(tab) \
51 ((struct acpi_whea_header *)((char *)(tab) + \
52 sizeof(struct acpi_table_erst)))
54 #define SPIN_UNIT 100 /* 100ns */
55 /* Firmware should respond within 1 miliseconds */
56 #define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC)
57 #define FIRMWARE_MAX_STALL 50 /* 50us */
60 EXPORT_SYMBOL_GPL(erst_disable
);
62 static struct acpi_table_erst
*erst_tab
;
64 /* ERST Error Log Address Range atrributes */
65 #define ERST_RANGE_RESERVED 0x0001
66 #define ERST_RANGE_NVRAM 0x0002
67 #define ERST_RANGE_SLOW 0x0004
70 * ERST Error Log Address Range, used as buffer for reading/writing
73 static struct erst_erange
{
81 * Prevent ERST interpreter to run simultaneously, because the
82 * corresponding firmware implementation may not work properly when
83 * invoked simultaneously.
85 * It is used to provide exclusive accessing for ERST Error Log
88 static DEFINE_SPINLOCK(erst_lock
);
90 static inline int erst_errno(int command_status
)
92 switch (command_status
) {
93 case ERST_STATUS_SUCCESS
:
95 case ERST_STATUS_HARDWARE_NOT_AVAILABLE
:
97 case ERST_STATUS_NOT_ENOUGH_SPACE
:
99 case ERST_STATUS_RECORD_STORE_EMPTY
:
100 case ERST_STATUS_RECORD_NOT_FOUND
:
107 static int erst_timedout(u64
*t
, u64 spin_unit
)
109 if ((s64
)*t
< spin_unit
) {
110 pr_warning(FW_WARN ERST_PFX
111 "Firmware does not respond in time\n");
116 touch_nmi_watchdog();
120 static int erst_exec_load_var1(struct apei_exec_context
*ctx
,
121 struct acpi_whea_header
*entry
)
123 return __apei_exec_read_register(entry
, &ctx
->var1
);
126 static int erst_exec_load_var2(struct apei_exec_context
*ctx
,
127 struct acpi_whea_header
*entry
)
129 return __apei_exec_read_register(entry
, &ctx
->var2
);
132 static int erst_exec_store_var1(struct apei_exec_context
*ctx
,
133 struct acpi_whea_header
*entry
)
135 return __apei_exec_write_register(entry
, ctx
->var1
);
138 static int erst_exec_add(struct apei_exec_context
*ctx
,
139 struct acpi_whea_header
*entry
)
141 ctx
->var1
+= ctx
->var2
;
145 static int erst_exec_subtract(struct apei_exec_context
*ctx
,
146 struct acpi_whea_header
*entry
)
148 ctx
->var1
-= ctx
->var2
;
152 static int erst_exec_add_value(struct apei_exec_context
*ctx
,
153 struct acpi_whea_header
*entry
)
158 rc
= __apei_exec_read_register(entry
, &val
);
162 rc
= __apei_exec_write_register(entry
, val
);
166 static int erst_exec_subtract_value(struct apei_exec_context
*ctx
,
167 struct acpi_whea_header
*entry
)
172 rc
= __apei_exec_read_register(entry
, &val
);
176 rc
= __apei_exec_write_register(entry
, val
);
180 static int erst_exec_stall(struct apei_exec_context
*ctx
,
181 struct acpi_whea_header
*entry
)
185 if (ctx
->value
> FIRMWARE_MAX_STALL
) {
187 pr_warning(FW_WARN ERST_PFX
188 "Too long stall time for stall instruction: %llx.\n",
190 stall_time
= FIRMWARE_MAX_STALL
;
192 stall_time
= ctx
->value
;
197 static int erst_exec_stall_while_true(struct apei_exec_context
*ctx
,
198 struct acpi_whea_header
*entry
)
202 u64 timeout
= FIRMWARE_TIMEOUT
;
205 if (ctx
->var1
> FIRMWARE_MAX_STALL
) {
207 pr_warning(FW_WARN ERST_PFX
208 "Too long stall time for stall while true instruction: %llx.\n",
210 stall_time
= FIRMWARE_MAX_STALL
;
212 stall_time
= ctx
->var1
;
215 rc
= __apei_exec_read_register(entry
, &val
);
218 if (val
!= ctx
->value
)
220 if (erst_timedout(&timeout
, stall_time
* NSEC_PER_USEC
))
226 static int erst_exec_skip_next_instruction_if_true(
227 struct apei_exec_context
*ctx
,
228 struct acpi_whea_header
*entry
)
233 rc
= __apei_exec_read_register(entry
, &val
);
236 if (val
== ctx
->value
) {
238 return APEI_EXEC_SET_IP
;
244 static int erst_exec_goto(struct apei_exec_context
*ctx
,
245 struct acpi_whea_header
*entry
)
247 ctx
->ip
= ctx
->value
;
248 return APEI_EXEC_SET_IP
;
251 static int erst_exec_set_src_address_base(struct apei_exec_context
*ctx
,
252 struct acpi_whea_header
*entry
)
254 return __apei_exec_read_register(entry
, &ctx
->src_base
);
257 static int erst_exec_set_dst_address_base(struct apei_exec_context
*ctx
,
258 struct acpi_whea_header
*entry
)
260 return __apei_exec_read_register(entry
, &ctx
->dst_base
);
263 static int erst_exec_move_data(struct apei_exec_context
*ctx
,
264 struct acpi_whea_header
*entry
)
269 rc
= __apei_exec_read_register(entry
, &offset
);
272 memmove((void *)ctx
->dst_base
+ offset
,
273 (void *)ctx
->src_base
+ offset
,
279 static struct apei_exec_ins_type erst_ins_type
[] = {
280 [ACPI_ERST_READ_REGISTER
] = {
281 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
282 .run
= apei_exec_read_register
,
284 [ACPI_ERST_READ_REGISTER_VALUE
] = {
285 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
286 .run
= apei_exec_read_register_value
,
288 [ACPI_ERST_WRITE_REGISTER
] = {
289 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
290 .run
= apei_exec_write_register
,
292 [ACPI_ERST_WRITE_REGISTER_VALUE
] = {
293 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
294 .run
= apei_exec_write_register_value
,
298 .run
= apei_exec_noop
,
300 [ACPI_ERST_LOAD_VAR1
] = {
301 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
302 .run
= erst_exec_load_var1
,
304 [ACPI_ERST_LOAD_VAR2
] = {
305 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
306 .run
= erst_exec_load_var2
,
308 [ACPI_ERST_STORE_VAR1
] = {
309 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
310 .run
= erst_exec_store_var1
,
314 .run
= erst_exec_add
,
316 [ACPI_ERST_SUBTRACT
] = {
318 .run
= erst_exec_subtract
,
320 [ACPI_ERST_ADD_VALUE
] = {
321 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
322 .run
= erst_exec_add_value
,
324 [ACPI_ERST_SUBTRACT_VALUE
] = {
325 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
326 .run
= erst_exec_subtract_value
,
328 [ACPI_ERST_STALL
] = {
330 .run
= erst_exec_stall
,
332 [ACPI_ERST_STALL_WHILE_TRUE
] = {
333 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
334 .run
= erst_exec_stall_while_true
,
336 [ACPI_ERST_SKIP_NEXT_IF_TRUE
] = {
337 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
338 .run
= erst_exec_skip_next_instruction_if_true
,
342 .run
= erst_exec_goto
,
344 [ACPI_ERST_SET_SRC_ADDRESS_BASE
] = {
345 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
346 .run
= erst_exec_set_src_address_base
,
348 [ACPI_ERST_SET_DST_ADDRESS_BASE
] = {
349 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
350 .run
= erst_exec_set_dst_address_base
,
352 [ACPI_ERST_MOVE_DATA
] = {
353 .flags
= APEI_EXEC_INS_ACCESS_REGISTER
,
354 .run
= erst_exec_move_data
,
358 static inline void erst_exec_ctx_init(struct apei_exec_context
*ctx
)
360 apei_exec_ctx_init(ctx
, erst_ins_type
, ARRAY_SIZE(erst_ins_type
),
361 ERST_TAB_ENTRY(erst_tab
), erst_tab
->entries
);
364 static int erst_get_erange(struct erst_erange
*range
)
366 struct apei_exec_context ctx
;
369 erst_exec_ctx_init(&ctx
);
370 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_ERROR_RANGE
);
373 range
->base
= apei_exec_ctx_get_output(&ctx
);
374 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_ERROR_LENGTH
);
377 range
->size
= apei_exec_ctx_get_output(&ctx
);
378 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_ERROR_ATTRIBUTES
);
381 range
->attr
= apei_exec_ctx_get_output(&ctx
);
386 static ssize_t
__erst_get_record_count(void)
388 struct apei_exec_context ctx
;
391 erst_exec_ctx_init(&ctx
);
392 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_RECORD_COUNT
);
395 return apei_exec_ctx_get_output(&ctx
);
398 ssize_t
erst_get_record_count(void)
406 spin_lock_irqsave(&erst_lock
, flags
);
407 count
= __erst_get_record_count();
408 spin_unlock_irqrestore(&erst_lock
, flags
);
412 EXPORT_SYMBOL_GPL(erst_get_record_count
);
414 static int __erst_get_next_record_id(u64
*record_id
)
416 struct apei_exec_context ctx
;
419 erst_exec_ctx_init(&ctx
);
420 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_RECORD_ID
);
423 *record_id
= apei_exec_ctx_get_output(&ctx
);
429 * Get the record ID of an existing error record on the persistent
430 * storage. If there is no error record on the persistent storage, the
431 * returned record_id is APEI_ERST_INVALID_RECORD_ID.
433 int erst_get_next_record_id(u64
*record_id
)
441 spin_lock_irqsave(&erst_lock
, flags
);
442 rc
= __erst_get_next_record_id(record_id
);
443 spin_unlock_irqrestore(&erst_lock
, flags
);
447 EXPORT_SYMBOL_GPL(erst_get_next_record_id
);
449 static int __erst_write_to_storage(u64 offset
)
451 struct apei_exec_context ctx
;
452 u64 timeout
= FIRMWARE_TIMEOUT
;
456 erst_exec_ctx_init(&ctx
);
457 rc
= apei_exec_run(&ctx
, ACPI_ERST_BEGIN_WRITE
);
460 apei_exec_ctx_set_input(&ctx
, offset
);
461 rc
= apei_exec_run(&ctx
, ACPI_ERST_SET_RECORD_OFFSET
);
464 rc
= apei_exec_run(&ctx
, ACPI_ERST_EXECUTE_OPERATION
);
468 rc
= apei_exec_run(&ctx
, ACPI_ERST_CHECK_BUSY_STATUS
);
471 val
= apei_exec_ctx_get_output(&ctx
);
474 if (erst_timedout(&timeout
, SPIN_UNIT
))
477 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_COMMAND_STATUS
);
480 val
= apei_exec_ctx_get_output(&ctx
);
481 rc
= apei_exec_run(&ctx
, ACPI_ERST_END
);
485 return erst_errno(val
);
488 static int __erst_read_from_storage(u64 record_id
, u64 offset
)
490 struct apei_exec_context ctx
;
491 u64 timeout
= FIRMWARE_TIMEOUT
;
495 erst_exec_ctx_init(&ctx
);
496 rc
= apei_exec_run(&ctx
, ACPI_ERST_BEGIN_READ
);
499 apei_exec_ctx_set_input(&ctx
, offset
);
500 rc
= apei_exec_run(&ctx
, ACPI_ERST_SET_RECORD_OFFSET
);
503 apei_exec_ctx_set_input(&ctx
, record_id
);
504 rc
= apei_exec_run(&ctx
, ACPI_ERST_SET_RECORD_ID
);
507 rc
= apei_exec_run(&ctx
, ACPI_ERST_EXECUTE_OPERATION
);
511 rc
= apei_exec_run(&ctx
, ACPI_ERST_CHECK_BUSY_STATUS
);
514 val
= apei_exec_ctx_get_output(&ctx
);
517 if (erst_timedout(&timeout
, SPIN_UNIT
))
520 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_COMMAND_STATUS
);
523 val
= apei_exec_ctx_get_output(&ctx
);
524 rc
= apei_exec_run(&ctx
, ACPI_ERST_END
);
528 return erst_errno(val
);
531 static int __erst_clear_from_storage(u64 record_id
)
533 struct apei_exec_context ctx
;
534 u64 timeout
= FIRMWARE_TIMEOUT
;
538 erst_exec_ctx_init(&ctx
);
539 rc
= apei_exec_run(&ctx
, ACPI_ERST_BEGIN_CLEAR
);
542 apei_exec_ctx_set_input(&ctx
, record_id
);
543 rc
= apei_exec_run(&ctx
, ACPI_ERST_SET_RECORD_ID
);
546 rc
= apei_exec_run(&ctx
, ACPI_ERST_EXECUTE_OPERATION
);
550 rc
= apei_exec_run(&ctx
, ACPI_ERST_CHECK_BUSY_STATUS
);
553 val
= apei_exec_ctx_get_output(&ctx
);
556 if (erst_timedout(&timeout
, SPIN_UNIT
))
559 rc
= apei_exec_run(&ctx
, ACPI_ERST_GET_COMMAND_STATUS
);
562 val
= apei_exec_ctx_get_output(&ctx
);
563 rc
= apei_exec_run(&ctx
, ACPI_ERST_END
);
567 return erst_errno(val
);
570 /* NVRAM ERST Error Log Address Range is not supported yet */
571 static void pr_unimpl_nvram(void)
573 if (printk_ratelimit())
575 "NVRAM ERST Log Address Range is not implemented yet\n");
578 static int __erst_write_to_nvram(const struct cper_record_header
*record
)
580 /* do not print message, because printk is not safe for NMI */
584 static int __erst_read_to_erange_from_nvram(u64 record_id
, u64
*offset
)
590 static int __erst_clear_from_nvram(u64 record_id
)
596 int erst_write(const struct cper_record_header
*record
)
600 struct cper_record_header
*rcd_erange
;
605 if (memcmp(record
->signature
, CPER_SIG_RECORD
, CPER_SIG_SIZE
))
608 if (erst_erange
.attr
& ERST_RANGE_NVRAM
) {
609 if (!spin_trylock_irqsave(&erst_lock
, flags
))
611 rc
= __erst_write_to_nvram(record
);
612 spin_unlock_irqrestore(&erst_lock
, flags
);
616 if (record
->record_length
> erst_erange
.size
)
619 if (!spin_trylock_irqsave(&erst_lock
, flags
))
621 memcpy(erst_erange
.vaddr
, record
, record
->record_length
);
622 rcd_erange
= erst_erange
.vaddr
;
623 /* signature for serialization system */
624 memcpy(&rcd_erange
->persistence_information
, "ER", 2);
626 rc
= __erst_write_to_storage(0);
627 spin_unlock_irqrestore(&erst_lock
, flags
);
631 EXPORT_SYMBOL_GPL(erst_write
);
633 static int __erst_read_to_erange(u64 record_id
, u64
*offset
)
637 if (erst_erange
.attr
& ERST_RANGE_NVRAM
)
638 return __erst_read_to_erange_from_nvram(
641 rc
= __erst_read_from_storage(record_id
, 0);
649 static ssize_t
__erst_read(u64 record_id
, struct cper_record_header
*record
,
654 struct cper_record_header
*rcd_tmp
;
656 rc
= __erst_read_to_erange(record_id
, &offset
);
659 rcd_tmp
= erst_erange
.vaddr
+ offset
;
660 len
= rcd_tmp
->record_length
;
662 memcpy(record
, rcd_tmp
, len
);
668 * If return value > buflen, the buffer size is not big enough,
669 * else if return value < 0, something goes wrong,
670 * else everything is OK, and return value is record length
672 ssize_t
erst_read(u64 record_id
, struct cper_record_header
*record
,
681 spin_lock_irqsave(&erst_lock
, flags
);
682 len
= __erst_read(record_id
, record
, buflen
);
683 spin_unlock_irqrestore(&erst_lock
, flags
);
686 EXPORT_SYMBOL_GPL(erst_read
);
689 * If return value > buflen, the buffer size is not big enough,
690 * else if return value = 0, there is no more record to read,
691 * else if return value < 0, something goes wrong,
692 * else everything is OK, and return value is record length
694 ssize_t
erst_read_next(struct cper_record_header
*record
, size_t buflen
)
704 spin_lock_irqsave(&erst_lock
, flags
);
705 rc
= __erst_get_next_record_id(&record_id
);
707 spin_unlock_irqrestore(&erst_lock
, flags
);
711 if (record_id
== APEI_ERST_INVALID_RECORD_ID
) {
712 spin_unlock_irqrestore(&erst_lock
, flags
);
716 len
= __erst_read(record_id
, record
, buflen
);
717 spin_unlock_irqrestore(&erst_lock
, flags
);
721 EXPORT_SYMBOL_GPL(erst_read_next
);
723 int erst_clear(u64 record_id
)
731 spin_lock_irqsave(&erst_lock
, flags
);
732 if (erst_erange
.attr
& ERST_RANGE_NVRAM
)
733 rc
= __erst_clear_from_nvram(record_id
);
735 rc
= __erst_clear_from_storage(record_id
);
736 spin_unlock_irqrestore(&erst_lock
, flags
);
740 EXPORT_SYMBOL_GPL(erst_clear
);
742 static int __init
setup_erst_disable(char *str
)
748 __setup("erst_disable", setup_erst_disable
);
750 static int erst_check_table(struct acpi_table_erst
*erst_tab
)
752 if (erst_tab
->header_length
!= sizeof(struct acpi_table_erst
))
754 if (erst_tab
->header
.length
< sizeof(struct acpi_table_erst
))
756 if (erst_tab
->entries
!=
757 (erst_tab
->header
.length
- sizeof(struct acpi_table_erst
)) /
758 sizeof(struct acpi_erst_entry
))
764 static int __init
erst_init(void)
768 struct apei_exec_context ctx
;
769 struct apei_resources erst_resources
;
777 "Error Record Serialization Table (ERST) support is disabled.\n");
781 status
= acpi_get_table(ACPI_SIG_ERST
, 0,
782 (struct acpi_table_header
**)&erst_tab
);
783 if (status
== AE_NOT_FOUND
) {
784 pr_err(ERST_PFX
"Table is not found!\n");
786 } else if (ACPI_FAILURE(status
)) {
787 const char *msg
= acpi_format_exception(status
);
788 pr_err(ERST_PFX
"Failed to get table, %s\n", msg
);
793 rc
= erst_check_table(erst_tab
);
795 pr_err(FW_BUG ERST_PFX
"ERST table is invalid\n");
799 apei_resources_init(&erst_resources
);
800 erst_exec_ctx_init(&ctx
);
801 rc
= apei_exec_collect_resources(&ctx
, &erst_resources
);
804 rc
= apei_resources_request(&erst_resources
, "APEI ERST");
807 rc
= apei_exec_pre_map_gars(&ctx
);
810 rc
= erst_get_erange(&erst_erange
);
814 "The corresponding hardware device or firmware implementation "
815 "is not available.\n");
818 "Failed to get Error Log Address Range.\n");
822 r
= request_mem_region(erst_erange
.base
, erst_erange
.size
, "APEI ERST");
825 "Can not request iomem region <0x%16llx-0x%16llx> for ERST.\n",
826 (unsigned long long)erst_erange
.base
,
827 (unsigned long long)erst_erange
.base
+ erst_erange
.size
);
832 erst_erange
.vaddr
= ioremap_cache(erst_erange
.base
,
834 if (!erst_erange
.vaddr
)
835 goto err_release_erange
;
838 "Error Record Serialization Table (ERST) support is initialized.\n");
843 release_mem_region(erst_erange
.base
, erst_erange
.size
);
845 apei_exec_post_unmap_gars(&ctx
);
847 apei_resources_release(&erst_resources
);
849 apei_resources_fini(&erst_resources
);
855 device_initcall(erst_init
);