Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1328022 > unrolled thread
| Started by | Tyler Baicar <tbaicar@codeaurora.org> |
|---|---|
| First post | 2016-02-05 20:20 +0100 |
| Last post | 2016-02-05 20:20 +0100 |
| Articles | 5 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH V1 0/6] Add UEFI 2.6 and ACPI 6.1 updates for RAS on ARM64 Tyler Baicar <tbaicar@codeaurora.org> - 2016-02-05 20:20 +0100
[PATCH V1 3/6] efi: parse ARMv8 processor error Tyler Baicar <tbaicar@codeaurora.org> - 2016-02-05 20:20 +0100
[PATCH V1 5/6] arm64: exception: handle instruction abort at current EL Tyler Baicar <tbaicar@codeaurora.org> - 2016-02-05 20:20 +0100
[PATCH V1 6/6] acpi: apei: handle SEA notification type for ARMv8 Tyler Baicar <tbaicar@codeaurora.org> - 2016-02-05 20:20 +0100
[PATCH V1 2/6] ras: acpi/apei: cper: generic error data entry v3 per ACPI 6.1 Tyler Baicar <tbaicar@codeaurora.org> - 2016-02-05 20:20 +0100
| From | Tyler Baicar <tbaicar@codeaurora.org> |
|---|---|
| Date | 2016-02-05 20:20 +0100 |
| Subject | [PATCH V1 0/6] Add UEFI 2.6 and ACPI 6.1 updates for RAS on ARM64 |
| Message-ID | <qYU5b-4l7-3@gated-at.bofh.it> |
Add support for Generic Hardware Error Source (GHES) v2, which introduces the
capability for the OS to acknowledge the consumption of the error record
generated by the Reliability, Availability and Serviceability (RAS) controller.
This eliminates potential race conditions between the OS and the RAS controller.
Add support for the timestamp field added to the Generic Error Data Entry v3,
allowing the OS to log the time that the error is generated by the firmware,
rather than the time the error is consumed. This improves the correctness of
event sequences when analyzing error logs. The timestamp is added in
ACPI 6.1, reference Table 18-343 Generic Error Data Entry.
Add support for ARMv8 Common Platform Error Record (CPER) per UEFI 2.6
specification. ARMv8 specific processor error information is reported as part of
the CPER records. This provides more detail on for processor error logs.
Synchronous External Abort (SEA) represents a specific processor error condition
in ARM systems. A handler is added to recognize SEA errors, and a notifier is
added to parse and report the errors before the process is killed. Refer to
section N.2.1.1 in the Common Platform Error Record appendix of the UEFI 2.6
specification.
Depends on: [PATCH v5] acpi, apei, arm64: APEI initial support for aarch64.
https://lkml.org/lkml/2015/12/10/131
Tyler Baicar (6):
acpi: apei: read ack upon ghes record consumption
ras: acpi/apei: cper: generic error data entry v3 per ACPI 6.1
efi: parse ARMv8 processor error
arm64: exception: handle Synchronous External Abort
arm64: exception: handle instruction abort at current EL
acpi: apei: handle SEA notification type for ARMv8
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/system_misc.h | 13 ++
arch/arm64/kernel/entry.S | 19 +++
arch/arm64/mm/fault.c | 58 +++++++--
drivers/acpi/apei/Kconfig | 13 ++
drivers/acpi/apei/ghes.c | 159 ++++++++++++++++++++++-
drivers/acpi/apei/hest.c | 7 +-
drivers/firmware/efi/cper.c | 244 ++++++++++++++++++++++++++++++++---
include/acpi/actbl1.h | 46 ++++++-
include/acpi/ghes.h | 1 +
include/linux/cper.h | 72 +++++++++++
11 files changed, 599 insertions(+), 34 deletions(-)
--
1.8.2.1
[toc] | [next] | [standalone]
| From | Tyler Baicar <tbaicar@codeaurora.org> |
|---|---|
| Date | 2016-02-05 20:20 +0100 |
| Subject | [PATCH V1 3/6] efi: parse ARMv8 processor error |
| Message-ID | <qYU5b-4l7-17@gated-at.bofh.it> |
| In reply to | #1328022 |
Add support for ARMv8 Common Platform Error Record (CPER).
UEFI 2.6 specification adds support for ARMv8 specific
processor error information to be reported as part of the
CPER records. This provides more detail on for processor error logs.
Signed-off-by: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org>
Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
Signed-off-by: Naveen Kaje <nkaje@codeaurora.org>
---
drivers/firmware/efi/cper.c | 136 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/cper.h | 72 +++++++++++++++++++++++
2 files changed, 208 insertions(+)
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index accd351..ca803fc 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -109,12 +109,15 @@ void cper_print_bits(const char *pfx, unsigned int bits,
static const char * const proc_type_strs[] = {
"IA32/X64",
"IA64",
+ "ARMv8",
};
static const char * const proc_isa_strs[] = {
"IA32",
"IA64",
"X64",
+ "ARM A32/T32",
+ "ARM A64",
};
static const char * const proc_error_type_strs[] = {
@@ -183,6 +186,127 @@ static void cper_print_proc_generic(const char *pfx,
printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
}
+static void cper_print_proc_armv8(const char *pfx,
+ const struct cper_sec_proc_armv8 *proc)
+{
+ int i, len;
+ struct cper_armv8_err_info *err_info;
+ __u64 *qword = NULL;
+ char newpfx[64];
+
+ printk("%ssection length: %d\n", pfx, proc->section_length);
+ printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
+
+ len = proc->section_length - (sizeof(*proc) +
+ proc->err_info_num * (sizeof(*err_info)));
+ if (len < 0) {
+ printk("%ssection length is too small.\n", pfx);
+ printk("%sERR_INFO_NUM is %d.\n", pfx, proc->err_info_num);
+ return;
+ }
+
+ if (proc->validation_bits & CPER_ARMV8_VALID_MPIDR)
+ printk("%sMPIDR: 0x%016llx\n", pfx, proc->mpidr);
+ if (proc->validation_bits & CPER_ARMV8_VALID_AFFINITY_LEVEL)
+ printk("%serror affinity level: %d\n", pfx,
+ proc->affinity_level);
+ if (proc->validation_bits & CPER_ARMV8_VALID_RUNNING_STATE)
+ printk("%srunning state: %d\n", pfx, proc->running_state);
+
+ snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
+
+ err_info = (struct cper_armv8_err_info *)(proc + 1);
+ for (i = 0; i < proc->err_info_num; i++) {
+ printk("%sError info structure %d:\n", pfx, i);
+ printk("%sversion:%d\n", newpfx, err_info->version);
+ printk("%slength:%d\n", newpfx, err_info->length);
+ if (err_info->validation_bits &
+ CPER_ARMV8_INFO_VALID_MULTI_ERR) {
+ if (err_info->multiple_error == 0)
+ printk("%ssingle error.\n", newpfx);
+ else if (err_info->multiple_error == 1)
+ printk("%smultiple errors.\n", newpfx);
+ else
+ printk("%smultiple errors count:%d.\n",
+ newpfx, err_info->multiple_error);
+ }
+ if (err_info->validation_bits & CPER_ARMV8_INFO_VALID_FLAGS) {
+ if (err_info->flags & CPER_ARMV8_INFO_FLAGS_FIRST)
+ printk("%sfirst error captured.\n", newpfx);
+ if (err_info->flags & CPER_ARMV8_INFO_FLAGS_LAST)
+ printk("%slast error captured.\n", newpfx);
+ if (err_info->flags & CPER_ARMV8_INFO_FLAGS_PROPAGATED)
+ printk("%spropagated error captured.\n",
+ newpfx);
+ }
+ printk("%serror_type: %d, %s\n", newpfx, err_info->type,
+ err_info->type < ARRAY_SIZE(proc_error_type_strs) ?
+ proc_error_type_strs[err_info->type] : "unknown");
+ printk("%serror_info: 0x%016llx\n", newpfx,
+ err_info->error_info);
+ if (err_info->validation_bits & CPER_ARMV8_INFO_VALID_VIRT_ADDR)
+ printk("%svirtual fault address: 0x%016llx\n",
+ newpfx, err_info->virt_fault_addr);
+ if (err_info->validation_bits &
+ CPER_ARMV8_INFO_VALID_PHYSICAL_ADDR)
+ printk("%sphysical fault address: 0x%016llx\n",
+ newpfx, err_info->physical_fault_addr);
+ err_info += 1;
+ }
+
+ if (len < sizeof(*qword) && proc->context_info_num > 0) {
+ printk("%ssection length is too small.\n", pfx);
+ printk("%sCTX_INFO_NUM is %d.\n", pfx, proc->context_info_num);
+ return;
+ }
+ for (i = 0; i < proc->context_info_num; i++) {
+ qword = (__u64 *)err_info;
+ printk("%sProcessor context info structure %d:\n", pfx, i);
+ printk("%sException level %d.\n", newpfx,
+ (int)((*qword & CPER_ARMV8_CTX_EL_MASK)
+ >> CPER_ARMV8_CTX_EL_SHIFT));
+ printk("%sSecure bit: %d.\n", newpfx,
+ (int)((*qword & CPER_ARMV8_CTX_NS_MASK)
+ >> CPER_ARMV8_CTX_NS_SHIFT));
+ if ((*qword & CPER_ARMV8_CTX_TYPE_MASK) == 0) {
+ if (len < CPER_AARCH32_CTX_LEN) {
+ printk("%ssection length is too small.\n", pfx);
+ printk("%sremaining length is %d.\n", pfx, len);
+ return;
+ }
+ printk("%sAArch32 execution context.\n", newpfx);
+ qword++;
+ print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
+ qword, CPER_AARCH32_CTX_LEN - sizeof(*qword),
+ 0);
+ len -= CPER_AARCH32_CTX_LEN;
+ } else if ((*qword & CPER_ARMV8_CTX_TYPE_MASK) == 1) {
+ if (len < CPER_AARCH64_CTX_LEN) {
+ printk("%ssection length is too small.\n", pfx);
+ printk("%sremaining length is %d.\n", pfx, len);
+ return;
+ }
+ printk("%sAArch64 execution context.\n", newpfx);
+ qword++;
+ print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
+ qword, CPER_AARCH64_CTX_LEN - sizeof(*qword),
+ 0);
+ len -= CPER_AARCH64_CTX_LEN;
+ } else {
+ printk("%scontext type is incorrect 0x%016llx.\n",
+ pfx, *qword);
+ return;
+ }
+ }
+
+ if (len > 0) {
+ printk("%sVendor specific error info has %d bytes.\n", pfx,
+ len);
+ print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, qword, len,
+ 0);
+ }
+}
+
static const char * const mem_err_type_strs[] = {
"unknown",
"no error",
@@ -446,6 +570,18 @@ static void cper_estatus_print_section(
cper_print_pcie(newpfx, pcie, gdata);
else
goto err_section_too_small;
+ } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARMV8)) {
+ struct cper_sec_proc_armv8 *armv8_err;
+
+ if (gdata_v3)
+ armv8_err = (void *)(gdata_v3 + 1);
+ else
+ armv8_err = (void *)(gdata + 1);
+ printk("%ssection_type: ARMv8 processor error\n", newpfx);
+ if (gdata->error_data_length >= sizeof(*armv8_err))
+ cper_print_proc_armv8(newpfx, armv8_err);
+ else
+ goto err_section_too_small;
} else
printk("%s""section type: unknown, %pUl\n", newpfx, sec_type);
diff --git a/include/linux/cper.h b/include/linux/cper.h
index dcacb1a..d1efbef 100644
--- a/include/linux/cper.h
+++ b/include/linux/cper.h
@@ -162,6 +162,11 @@ enum {
* corrective action before the data is consumed
*/
#define CPER_SEC_LATENT_ERROR 0x0020
+/*
+ * If set, the section contains an error that is propagated. The error
+ * did not originate from the hardware associated with this section.
+ */
+#define CPER_SEC_PROPAGATED 0x0040
/*
* Section type definitions, used in section_type field in struct
@@ -180,6 +185,10 @@ enum {
#define CPER_SEC_PROC_IPF \
UUID_LE(0xE429FAF1, 0x3CB7, 0x11D4, 0x0B, 0xCA, 0x07, 0x00, \
0x80, 0xC7, 0x3C, 0x88, 0x81)
+/* Processor Specific: ARMv8 */
+#define CPER_SEC_PROC_ARMV8 \
+ UUID_LE(0xE19E3D16, 0xBC11, 0x11E4, 0x9C, 0xAA, 0xC2, 0x05, \
+ 0x1D, 0x5D, 0x46, 0xB0)
/* Platform Memory */
#define CPER_SEC_PLATFORM_MEM \
UUID_LE(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83, \
@@ -255,6 +264,34 @@ enum {
#define CPER_PCIE_SLOT_SHIFT 3
+#define CPER_ARMV8_ERR_INFO_NUM_MASK 0x00000000000000FF
+#define CPER_ARMV8_CTX_INFO_NUM_MASK 0x0000000000FFFF00
+#define CPER_ARMV8_CTX_INFO_NUM_SHIFT 8
+
+#define CPER_ARMV8_VALID_MPIDR 0x00000001
+#define CPER_ARMV8_VALID_AFFINITY_LEVEL 0x00000002
+#define CPER_ARMV8_VALID_RUNNING_STATE 0x00000004
+#define CPER_ARMV8_VALID_VENDOR_INFO 0x00000008
+
+#define CPER_ARMV8_INFO_VALID_MULTI_ERR 0x0001
+#define CPER_ARMV8_INFO_VALID_FLAGS 0x0002
+#define CPER_ARMV8_INFO_VALID_ERR_INFO 0x0004
+#define CPER_ARMV8_INFO_VALID_VIRT_ADDR 0x0008
+#define CPER_ARMV8_INFO_VALID_PHYSICAL_ADDR 0x0010
+
+#define CPER_ARMV8_INFO_FLAGS_FIRST 0x0001
+#define CPER_ARMV8_INFO_FLAGS_LAST 0x0002
+#define CPER_ARMV8_INFO_FLAGS_PROPAGATED 0x0004
+
+#define CPER_AARCH64_CTX_LEN 368
+#define CPER_AARCH32_CTX_LEN 256
+
+#define CPER_ARMV8_CTX_TYPE_MASK 0x000000000000000F
+#define CPER_ARMV8_CTX_EL_MASK 0x0000000000000070
+#define CPER_ARMV8_CTX_NS_MASK 0x0000000000000080
+#define CPER_ARMV8_CTX_EL_SHIFT 4
+#define CPER_ARMV8_CTX_NS_SHIFT 7
+
/*
* All tables and structs must be byte-packed to match CPER
* specification, since the tables are provided by the system BIOS
@@ -340,6 +377,41 @@ struct cper_ia_proc_ctx {
__u64 mm_reg_addr;
};
+/* ARMv8 Processor Error Section */
+struct cper_sec_proc_armv8 {
+ __u32 validation_bits;
+ __u16 err_info_num; /* Number of Processor Error Info */
+ __u16 context_info_num; /* Number of Processor Context Info Records*/
+ __u32 section_length;
+ __u8 affinity_level;
+ __u8 reserved[3]; /* must be zero */
+ __u64 mpidr;
+ __u64 midr;
+ __u32 running_state; /* Bit 0 set - Processor running. PSCI = 0 */
+ __u32 psci_state;
+};
+
+/* ARMv8 Processor Error Information Structure */
+struct cper_armv8_err_info {
+ __u8 version;
+ __u8 length;
+ __u16 validation_bits;
+ __u8 type;
+ __u16 multiple_error;
+ __u8 flags;
+ __u64 error_info;
+ __u64 virt_fault_addr;
+ __u64 physical_fault_addr;
+};
+
+/* ARMv8 AARCH64 Processor Context Information Structure */
+struct cper_armv8_aarch64_ctx {
+ __u8 type_el_ns;
+ __u8 reserved[7]; /* must be zero */
+ __u8 gpr[288];
+ __u8 spr[68];
+};
+
/* Old Memory Error Section UEFI 2.1, 2.2 */
struct cper_sec_mem_err_old {
__u64 validation_bits;
--
1.8.2.1
[toc] | [prev] | [next] | [standalone]
| From | Tyler Baicar <tbaicar@codeaurora.org> |
|---|---|
| Date | 2016-02-05 20:20 +0100 |
| Subject | [PATCH V1 5/6] arm64: exception: handle instruction abort at current EL |
| Message-ID | <qYU5c-4l7-31@gated-at.bofh.it> |
| In reply to | #1328022 |
Add a handler for instruction aborts at the current EL (ESR_ELx_EC_IABT_CUR) so they are no longer handled in el1_inv. This allows firmware first handling for possible SEA (Synchronous External Abort) caused instruction abort at current EL. Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org> Signed-off-by: Naveen Kaje <nkaje@codeaurora.org> --- arch/arm64/kernel/entry.S | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 1f7f5a2..6b7fb14 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -336,6 +336,8 @@ el1_sync: lsr x24, x1, #ESR_ELx_EC_SHIFT // exception class cmp x24, #ESR_ELx_EC_DABT_CUR // data abort in EL1 b.eq el1_da + cmp x24, #ESR_ELx_EC_IABT_CUR // instruction abort in EL1 + b.eq el1_ia cmp x24, #ESR_ELx_EC_SYS64 // configurable trap b.eq el1_undef cmp x24, #ESR_ELx_EC_SP_ALIGN // stack alignment exception @@ -363,6 +365,23 @@ el1_da: // disable interrupts before pulling preserved data off the stack disable_irq kernel_exit 1 +el1_ia: + /* + * Instruction abort handling + */ + mrs x0, far_el1 + enable_dbg + // re-enable interrupts if they were enabled in the aborted context + tbnz x23, #7, 1f // PSR_I_BIT + enable_irq +1: + orr x1, x1, #1 << 24 // use reserved ISS bit for instruction aborts + mov x2, sp // struct pt_regs + bl do_mem_abort + + // disable interrupts before pulling preserved data off the stack + disable_irq + kernel_exit 1 el1_sp_pc: /* * Stack or PC alignment exception handling -- 1.8.2.1
[toc] | [prev] | [next] | [standalone]
| From | Tyler Baicar <tbaicar@codeaurora.org> |
|---|---|
| Date | 2016-02-05 20:20 +0100 |
| Subject | [PATCH V1 6/6] acpi: apei: handle SEA notification type for ARMv8 |
| Message-ID | <qYU5c-4l7-39@gated-at.bofh.it> |
| In reply to | #1328022 |
ARM APEI extension proposal added SEA (Synchrounous External
Abort) notification type for ARMv8.
Add a new GHES error source handling function for SEA. If an error
source's notification type is SEA, then this function can be registered
into the SEA exception handler. That way GHES will parse and report
SEA exceptions when they occur.
Signed-off-by: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org>
Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
Signed-off-by: Naveen Kaje <nkaje@codeaurora.org>
---
arch/arm64/Kconfig | 1 +
drivers/acpi/apei/Kconfig | 13 ++++++++
drivers/acpi/apei/ghes.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++
include/acpi/actbl1.h | 6 +++-
4 files changed, 102 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 6e4a4f4..236f398 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -6,6 +6,7 @@ config ARM64
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
select ARCH_HAS_DEVMEM_IS_ALLOWED
select HAVE_ACPI_APEI if ACPI
+ select HAVE_ACPI_APEI_SEA if ACPI
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_GCOV_PROFILE_ALL
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index a60bb00..bfcbb9e 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -7,6 +7,19 @@ config HAVE_ACPI_APEI_NMI
config HAVE_ACPI_APEI_HEST_IA32
bool
+config HAVE_ACPI_APEI_SEA
+ bool "APEI Synchronous External Abort logging/recovering support"
+ help
+ This option should be enabled if the system supports
+ firmware first handling of SEA (Synchronous External Abort).
+ SEA happens with certain faults of data abort or instruction
+ abort synchronous exceptions on ARMv8 systems. If a system
+ supports firmware first handling of SEA, the platform analyzes
+ and handles hardware error notifications with SEA, and it may then
+ form a HW error record for the OS to parse and handle. This
+ option allows the OS to look for such HW error record, and
+ take appropriate action.
+
config ACPI_APEI
bool "ACPI Platform Error Interface (APEI)"
select MISC_FILESYSTEMS
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 6c68100..ed64b97 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -50,6 +50,10 @@
#include <acpi/apei.h>
#include <asm/tlbflush.h>
+#ifdef CONFIG_HAVE_ACPI_APEI_SEA
+#include <asm/system_misc.h>
+#endif
+
#include "apei-internal.h"
#define GHES_PFX "GHES: "
@@ -784,6 +788,62 @@ static struct notifier_block ghes_notifier_sci = {
.notifier_call = ghes_notify_sci,
};
+#ifdef CONFIG_HAVE_ACPI_APEI_SEA
+static LIST_HEAD(ghes_sea);
+
+static int ghes_notify_sea(struct notifier_block *this,
+ unsigned long event, void *data)
+{
+ struct ghes *ghes;
+ int ret = NOTIFY_DONE;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ghes, &ghes_sea, list) {
+ if (!ghes_proc(ghes))
+ ret = NOTIFY_OK;
+ }
+ rcu_read_unlock();
+
+ return ret;
+}
+
+static struct notifier_block ghes_notifier_sea = {
+ .notifier_call = ghes_notify_sea,
+};
+
+static int ghes_sea_add(struct ghes *ghes)
+{
+ mutex_lock(&ghes_list_mutex);
+ if (list_empty(&ghes_sea))
+ sea_register_handler_chain(&ghes_notifier_sea);
+ list_add_rcu(&ghes->list, &ghes_sea);
+ mutex_unlock(&ghes_list_mutex);
+ return 0;
+}
+
+static void ghes_sea_remove(struct ghes *ghes)
+{
+ mutex_lock(&ghes_list_mutex);
+ list_del_rcu(&ghes->list);
+ if (list_empty(&ghes_sea))
+ sea_unregister_handler_chain(&ghes_notifier_sea);
+ mutex_unlock(&ghes_list_mutex);
+}
+#else /* CONFIG_HAVE_ACPI_APEI_SEA */
+static inline int ghes_sea_add(struct ghes *ghes)
+{
+ pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n",
+ ghes->generic->header.source_id);
+ return -ENOTSUPP;
+}
+
+static inline void ghes_sea_remove(struct ghes *ghes)
+{
+ pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n",
+ ghes->generic->header.source_id);
+}
+#endif /* CONFIG_HAVE_ACPI_APEI_SEA */
+
#ifdef CONFIG_HAVE_ACPI_APEI_NMI
/*
* printk is not safe in NMI context. So in NMI handler, we allocate
@@ -1028,6 +1088,14 @@ static int ghes_probe(struct platform_device *ghes_dev)
case ACPI_HEST_NOTIFY_EXTERNAL:
case ACPI_HEST_NOTIFY_SCI:
break;
+ case ACPI_HEST_NOTIFY_SEA:
+ if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_SEA)) {
+ pr_warn(GHES_PFX "Generic hardware error source: %d notified via SEA is not supported\n",
+ generic->header.source_id);
+ rc = -ENOTSUPP;
+ goto err;
+ }
+ break;
case ACPI_HEST_NOTIFY_NMI:
if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) {
pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n",
@@ -1039,6 +1107,13 @@ static int ghes_probe(struct platform_device *ghes_dev)
pr_warning(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n",
generic->header.source_id);
goto err;
+ case ACPI_HEST_NOTIFY_GPIO:
+ case ACPI_HEST_NOTIFY_SEI:
+ case ACPI_HEST_NOTIFY_GSIV:
+ pr_warn(GHES_PFX "Generic hardware error source: %d notified via notification type %u is not supported\n",
+ generic->header.source_id, generic->header.source_id);
+ rc = -ENOTSUPP;
+ goto err;
default:
pr_warning(FW_WARN GHES_PFX "Unknown notification type: %u for generic hardware error source: %d\n",
generic->notify.type, generic->header.source_id);
@@ -1093,6 +1168,11 @@ static int ghes_probe(struct platform_device *ghes_dev)
list_add_rcu(&ghes->list, &ghes_sci);
mutex_unlock(&ghes_list_mutex);
break;
+ case ACPI_HEST_NOTIFY_SEA:
+ rc = ghes_sea_add(ghes);
+ if (rc)
+ goto err_edac_unreg;
+ break;
case ACPI_HEST_NOTIFY_NMI:
ghes_nmi_add(ghes);
break;
@@ -1135,6 +1215,9 @@ static int ghes_remove(struct platform_device *ghes_dev)
unregister_acpi_hed_notifier(&ghes_notifier_sci);
mutex_unlock(&ghes_list_mutex);
break;
+ case ACPI_HEST_NOTIFY_SEA:
+ ghes_sea_remove(ghes);
+ break;
case ACPI_HEST_NOTIFY_NMI:
ghes_nmi_remove(ghes);
break;
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index 231ae1e..e5118fb 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -507,7 +507,11 @@ enum acpi_hest_notify_types {
ACPI_HEST_NOTIFY_NMI = 4,
ACPI_HEST_NOTIFY_CMCI = 5, /* ACPI 5.0 */
ACPI_HEST_NOTIFY_MCE = 6, /* ACPI 5.0 */
- ACPI_HEST_NOTIFY_RESERVED = 7 /* 7 and greater are reserved */
+ ACPI_HEST_NOTIFY_GPIO = 7, /* ACPI 5.0 */
+ ACPI_HEST_NOTIFY_SEA = 8, /* ACPI 6.x */
+ ACPI_HEST_NOTIFY_SEI = 9, /* ACPI 6.x */
+ ACPI_HEST_NOTIFY_GSIV = 10, /* ACPI 6.x */
+ ACPI_HEST_NOTIFY_RESERVED = 11 /* 11 and greater are reserved */
};
/* Values for config_write_enable bitfield above */
--
1.8.2.1
[toc] | [prev] | [next] | [standalone]
| From | Tyler Baicar <tbaicar@codeaurora.org> |
|---|---|
| Date | 2016-02-05 20:20 +0100 |
| Subject | [PATCH V1 2/6] ras: acpi/apei: cper: generic error data entry v3 per ACPI 6.1 |
| Message-ID | <qYU5d-4l7-45@gated-at.bofh.it> |
| In reply to | #1328022 |
Currently when a RAS error is reported it is not timestamped.
The ACPI 6.1 spec adds the timestamp field to the generic error
data entry v3 structure. The timestamp of when the firmware
generated the error is now being reported.
Signed-off-by: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org>
Signed-off-by: Richard Ruigrok <rruigrok@codeaurora.org>
Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
Signed-off-by: Naveen Kaje <nkaje@codeaurora.org>
---
drivers/acpi/apei/ghes.c | 35 ++++++++++++--
drivers/firmware/efi/cper.c | 108 +++++++++++++++++++++++++++++++++++++-------
include/acpi/actbl1.h | 19 ++++++++
3 files changed, 142 insertions(+), 20 deletions(-)
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index db67711..6c68100 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -414,7 +414,15 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int
int flags = -1;
int sec_sev = ghes_severity(gdata->error_severity);
struct cper_sec_mem_err *mem_err;
- mem_err = (struct cper_sec_mem_err *)(gdata + 1);
+ struct acpi_hest_generic_data_v3 *gdata_v3 = NULL;
+
+ if ((gdata->revision >> 8) >= 0x03)
+ gdata_v3 = (struct acpi_hest_generic_data_v3 *)gdata;
+
+ if (gdata_v3)
+ mem_err = (struct cper_sec_mem_err *)(gdata_v3 + 1);
+ else
+ mem_err = (struct cper_sec_mem_err *)(gdata + 1);
if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
return;
@@ -444,14 +452,27 @@ static void ghes_do_proc(struct ghes *ghes,
{
int sev, sec_sev;
struct acpi_hest_generic_data *gdata;
+ struct acpi_hest_generic_data_v3 *gdata_v3 = NULL;
+ uuid_le sec_type;
sev = ghes_severity(estatus->error_severity);
apei_estatus_for_each_section(estatus, gdata) {
sec_sev = ghes_severity(gdata->error_severity);
- if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
+ sec_type = *(uuid_le *)gdata->section_type;
+
+ if ((gdata->revision >> 8) >= 0x03)
+ gdata_v3 = (struct acpi_hest_generic_data_v3 *)gdata;
+
+ if (!uuid_le_cmp(sec_type,
CPER_SEC_PLATFORM_MEM)) {
struct cper_sec_mem_err *mem_err;
- mem_err = (struct cper_sec_mem_err *)(gdata+1);
+
+ if (gdata_v3)
+ mem_err = (struct cper_sec_mem_err *)
+ (gdata_v3 + 1);
+ else
+ mem_err = (struct cper_sec_mem_err *)
+ (gdata + 1);
ghes_edac_report_mem_error(ghes, sev, mem_err);
arch_apei_report_mem_error(sev, mem_err);
@@ -461,7 +482,13 @@ static void ghes_do_proc(struct ghes *ghes,
else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
CPER_SEC_PCIE)) {
struct cper_sec_pcie *pcie_err;
- pcie_err = (struct cper_sec_pcie *)(gdata+1);
+
+ if (gdata_v3)
+ pcie_err = (struct cper_sec_pcie *)
+ (gdata_v3 + 1);
+ else
+ pcie_err = (struct cper_sec_pcie *)
+ (gdata + 1);
if (sev == GHES_SEV_RECOVERABLE &&
sec_sev == GHES_SEV_RECOVERABLE &&
pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index d425374..accd351 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -32,6 +32,8 @@
#include <linux/acpi.h>
#include <linux/pci.h>
#include <linux/aer.h>
+#include <linux/printk.h>
+#include <linux/bcd.h>
#define INDENT_SP " "
@@ -392,6 +394,10 @@ static void cper_estatus_print_section(
uuid_le *sec_type = (uuid_le *)gdata->section_type;
__u16 severity;
char newpfx[64];
+ struct acpi_hest_generic_data_v3 *gdata_v3 = NULL;
+
+ if ((gdata->revision >> 8) >= 0x03)
+ gdata_v3 = (struct acpi_hest_generic_data_v3 *)gdata;
severity = gdata->error_severity;
printk("%s""Error %d, type: %s\n", pfx, sec_no,
@@ -403,14 +409,24 @@ static void cper_estatus_print_section(
snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) {
- struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1);
+ struct cper_sec_proc_generic *proc_err;
+
+ if (gdata_v3)
+ proc_err = (void *)(gdata_v3 + 1);
+ else
+ proc_err = (void *)(gdata + 1);
printk("%s""section_type: general processor error\n", newpfx);
if (gdata->error_data_length >= sizeof(*proc_err))
cper_print_proc_generic(newpfx, proc_err);
else
goto err_section_too_small;
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
- struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
+ struct cper_sec_mem_err *mem_err;
+
+ if (gdata_v3)
+ mem_err = (void *)(gdata_v3 + 1);
+ else
+ mem_err = (void *)(gdata + 1);
printk("%s""section_type: memory error\n", newpfx);
if (gdata->error_data_length >=
sizeof(struct cper_sec_mem_err_old))
@@ -419,7 +435,12 @@ static void cper_estatus_print_section(
else
goto err_section_too_small;
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
- struct cper_sec_pcie *pcie = (void *)(gdata + 1);
+ struct cper_sec_pcie *pcie;
+
+ if (gdata_v3)
+ pcie = (void *)(gdata_v3 + 1);
+ else
+ pcie = (void *)(gdata + 1);
printk("%s""section_type: PCIe error\n", newpfx);
if (gdata->error_data_length >= sizeof(*pcie))
cper_print_pcie(newpfx, pcie, gdata);
@@ -434,10 +455,36 @@ err_section_too_small:
pr_err(FW_WARN "error section length is too small\n");
}
+static void cper_estatus_print_section_v3(const char *pfx,
+ const struct acpi_hest_generic_data_v3 *gdata, int sec_no)
+{
+ __u8 hour, min, sec, day, mon, *timestamp;
+ __u16 year;
+
+ if (gdata->gdata_v2.validation_bits & GED_VALID_TIMESTAMP) {
+ timestamp = (__u8 *)&(gdata->timestamp);
+ memcpy(&sec, timestamp, 1);
+ memcpy(&min, timestamp + 1, 1);
+ memcpy(&hour, timestamp + 2, 1);
+ memcpy(&day, timestamp + 4, 1);
+ memcpy(&mon, timestamp + 5, 1);
+ memcpy(&year, timestamp + 6, 2);
+ printk("%stime: ", pfx);
+ printk("%7s", 0x01 & *(timestamp + 3) ? "precise" : "");
+ printk(" %02d:%02d:%02d %04d-%02d-%02d\n",
+ bcd2bin(hour), bcd2bin(min), bcd2bin(sec),
+ year, bcd2bin(mon),
+ bcd2bin(day));
+ }
+
+ cper_estatus_print_section(pfx, &(gdata->gdata_v2), sec_no);
+}
+
void cper_estatus_print(const char *pfx,
const struct acpi_hest_generic_status *estatus)
{
struct acpi_hest_generic_data *gdata;
+ struct acpi_hest_generic_data_v3 *gdata_v3 = NULL;
unsigned int data_len, gedata_len;
int sec_no = 0;
char newpfx[64];
@@ -451,13 +498,27 @@ void cper_estatus_print(const char *pfx,
printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
data_len = estatus->data_length;
gdata = (struct acpi_hest_generic_data *)(estatus + 1);
+ if ((gdata->revision >> 8) >= 0x03)
+ gdata_v3 = (struct acpi_hest_generic_data_v3 *)gdata;
+
snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
- while (data_len >= sizeof(*gdata)) {
- gedata_len = gdata->error_data_length;
- cper_estatus_print_section(newpfx, gdata, sec_no);
- data_len -= gedata_len + sizeof(*gdata);
- gdata = (void *)(gdata + 1) + gedata_len;
- sec_no++;
+
+ if (gdata_v3) {
+ while (data_len >= sizeof(*gdata_v3)) {
+ gedata_len = gdata_v3->gdata_v2.error_data_length;
+ cper_estatus_print_section_v3(newpfx, gdata_v3, sec_no);
+ data_len -= gedata_len + sizeof(*gdata_v3);
+ gdata_v3 = (void *)(gdata_v3 + 1) + gedata_len;
+ sec_no++;
+ }
+ } else {
+ while (data_len >= sizeof(*gdata)) {
+ gedata_len = gdata->error_data_length;
+ cper_estatus_print_section(newpfx, gdata, sec_no);
+ data_len -= gedata_len + sizeof(*gdata);
+ gdata = (void *)(gdata + 1) + gedata_len;
+ sec_no++;
+ }
}
}
EXPORT_SYMBOL_GPL(cper_estatus_print);
@@ -478,6 +539,7 @@ EXPORT_SYMBOL_GPL(cper_estatus_check_header);
int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
{
struct acpi_hest_generic_data *gdata;
+ struct acpi_hest_generic_data_v3 *gdata_v3 = NULL;
unsigned int data_len, gedata_len;
int rc;
@@ -486,15 +548,29 @@ int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
return rc;
data_len = estatus->data_length;
gdata = (struct acpi_hest_generic_data *)(estatus + 1);
- while (data_len >= sizeof(*gdata)) {
- gedata_len = gdata->error_data_length;
- if (gedata_len > data_len - sizeof(*gdata))
+
+ if ((gdata->revision >> 8) >= 0x03) {
+ gdata_v3 = (struct acpi_hest_generic_data_v3 *)gdata;
+ while (data_len >= sizeof(*gdata_v3)) {
+ gedata_len = gdata_v3->gdata_v2.error_data_length;
+ if (gedata_len > data_len - sizeof(*gdata_v3))
+ return -EINVAL;
+ data_len -= gedata_len + sizeof(*gdata_v3);
+ gdata_v3 = (void *)(gdata_v3 + 1) + gedata_len;
+ }
+ if (data_len)
+ return -EINVAL;
+ } else {
+ while (data_len >= sizeof(*gdata)) {
+ gedata_len = gdata->error_data_length;
+ if (gedata_len > data_len - sizeof(*gdata))
+ return -EINVAL;
+ data_len -= gedata_len + sizeof(*gdata);
+ gdata = (void *)(gdata + 1) + gedata_len;
+ }
+ if (data_len)
return -EINVAL;
- data_len -= gedata_len + sizeof(*gdata);
- gdata = (void *)(gdata + 1) + gedata_len;
}
- if (data_len)
- return -EINVAL;
return 0;
}
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index 82695c9..231ae1e 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -653,6 +653,25 @@ struct acpi_hest_generic_data {
u8 fru_text[20];
};
+/* Generic Error Data entry version 3 as defined by ACPI 6.1 spec */
+
+struct acpi_hest_generic_data_v3 {
+ struct acpi_hest_generic_data gdata_v2;
+ __u64 timestamp;
+};
+
+/*
+ * Validation bits definition for validation_bits in struct
+ * acpi_hest_generic_data[_v3]. If set, corresponding fields in
+ * the struct contain valid information.
+ */
+/* corresponds fru_id */
+#define GED_VALID_FRU_ID 0x0001
+/* corresponds fru_text */
+#define GED_VALID_FRU_TEXT 0x0002
+/* corresponds timestamp */
+#define GED_VALID_TIMESTAMP 0x0004
+
/*******************************************************************************
*
* MADT - Multiple APIC Description Table
--
1.8.2.1
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web