ras: acpi / apei: generate trace event for unrecognized CPER section
authorTyler Baicar <tbaicar@codeaurora.org>
Wed, 21 Jun 2017 18:17:12 +0000 (12:17 -0600)
committerWill Deacon <will.deacon@arm.com>
Thu, 22 Jun 2017 17:22:04 +0000 (18:22 +0100)
The UEFI spec includes non-standard section type support in the
Common Platform Error Record. This is defined in section N.2.3 of
UEFI version 2.5.

Currently if the CPER section's type (UUID) does not match any
section type that the kernel knows how to parse, a trace event is
not generated.

Generate a trace event which contains the raw error data for
non-standard section type error records.

Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
CC: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org>
Tested-by: Shiju Jose <shiju.jose@huawei.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
drivers/acpi/apei/ghes.c
drivers/ras/ras.c
include/linux/ras.h
include/linux/uuid.h
include/ras/ras_event.h

index 7a91ac7d6b75896a330f4100a1ee7059fb07c89d..ab36ad628c680f5a7258de9ff99d530a46e2c61f 100644 (file)
 #include <linux/aer.h>
 #include <linux/nmi.h>
 #include <linux/sched/clock.h>
+#include <linux/uuid.h>
+#include <linux/ras.h>
 
 #include <acpi/actbl1.h>
 #include <acpi/ghes.h>
 #include <acpi/apei.h>
 #include <asm/tlbflush.h>
+#include <ras/ras_event.h>
 
 #include "apei-internal.h"
 
@@ -461,11 +464,19 @@ static void ghes_do_proc(struct ghes *ghes,
        int sev, sec_sev;
        struct acpi_hest_generic_data *gdata;
        guid_t *sec_type;
+       guid_t *fru_id = &NULL_UUID_LE;
+       char *fru_text = "";
 
        sev = ghes_severity(estatus->error_severity);
        apei_estatus_for_each_section(estatus, gdata) {
                sec_type = (guid_t *)gdata->section_type;
                sec_sev = ghes_severity(gdata->error_severity);
+               if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
+                       fru_id = (guid_t *)gdata->fru_id;
+
+               if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
+                       fru_text = gdata->fru_text;
+
                if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
                        struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
 
@@ -506,6 +517,13 @@ static void ghes_do_proc(struct ghes *ghes,
 
                }
 #endif
+               else {
+                       void *err = acpi_hest_get_payload(gdata);
+
+                       log_non_standard_event(sec_type, fru_id, fru_text,
+                                              sec_sev, err,
+                                              gdata->error_data_length);
+               }
        }
 }
 
index 94f8038864b4eeabea875b1fb888efcff52b517d..e87fd9e32ee27be7c92b828ee49345116d71edf1 100644 (file)
@@ -7,11 +7,19 @@
 
 #include <linux/init.h>
 #include <linux/ras.h>
+#include <linux/uuid.h>
 
 #define CREATE_TRACE_POINTS
 #define TRACE_INCLUDE_PATH ../../include/ras
 #include <ras/ras_event.h>
 
+void log_non_standard_event(const uuid_le *sec_type, const uuid_le *fru_id,
+                           const char *fru_text, const u8 sev, const u8 *err,
+                           const u32 len)
+{
+       trace_non_standard_event(sec_type, fru_id, fru_text, sev, err, len);
+}
+
 static int __init ras_init(void)
 {
        int rc = 0;
@@ -27,7 +35,7 @@ subsys_initcall(ras_init);
 EXPORT_TRACEPOINT_SYMBOL_GPL(extlog_mem_event);
 #endif
 EXPORT_TRACEPOINT_SYMBOL_GPL(mc_event);
-
+EXPORT_TRACEPOINT_SYMBOL_GPL(non_standard_event);
 
 int __init parse_ras_param(char *str)
 {
index ffb147185e8df8ae62e4566d7da1b666fc290e1a..62fac3042dceaa8f25b641fd4fe5c506d20410a7 100644 (file)
@@ -2,6 +2,7 @@
 #define __RAS_H__
 
 #include <asm/errno.h>
+#include <linux/uuid.h>
 
 #ifdef CONFIG_DEBUG_FS
 int ras_userspace_consumers(void);
@@ -22,4 +23,15 @@ static inline void __init cec_init(void)     { }
 static inline int cec_add_elem(u64 pfn)                { return -ENODEV; }
 #endif
 
+#ifdef CONFIG_RAS
+void log_non_standard_event(const guid_t *sec_type,
+                           const guid_t *fru_id, const char *fru_text,
+                           const u8 sev, const u8 *err, const u32 len);
+#else
+static void log_non_standard_event(const guid_t *sec_type,
+                                  const guid_t *fru_id, const char *fru_text,
+                                  const u8 sev, const u8 *err,
+                                  const u32 len) { return; }
+#endif
+
 #endif /* __RAS_H__ */
index 75f7182d5360bf5b58688ea349b54c218679ff58..61641faca38be48b2295b7ef76141ec56842ced2 100644 (file)
 
 #include <uapi/linux/uuid.h>
 
+#define UUID_SIZE 16
+
 typedef struct {
-       __u8 b[16];
+       __u8 b[UUID_SIZE];
 } uuid_t;
 
 #define UUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)                     \
index 1791a12cfa85e9875a8972826c01085d916a751e..4f79ba94fa6bd69ce3d229e9823f73f4d73f4b1f 100644 (file)
@@ -161,6 +161,51 @@ TRACE_EVENT(mc_event,
                  __get_str(driver_detail))
 );
 
+/*
+ * Non-Standard Section Report
+ *
+ * This event is generated when hardware detected a hardware
+ * error event, which may be of non-standard section as defined
+ * in UEFI spec appendix "Common Platform Error Record", or may
+ * be of sections for which TRACE_EVENT is not defined.
+ *
+ */
+TRACE_EVENT(non_standard_event,
+
+       TP_PROTO(const uuid_le *sec_type,
+                const uuid_le *fru_id,
+                const char *fru_text,
+                const u8 sev,
+                const u8 *err,
+                const u32 len),
+
+       TP_ARGS(sec_type, fru_id, fru_text, sev, err, len),
+
+       TP_STRUCT__entry(
+               __array(char, sec_type, UUID_SIZE)
+               __array(char, fru_id, UUID_SIZE)
+               __string(fru_text, fru_text)
+               __field(u8, sev)
+               __field(u32, len)
+               __dynamic_array(u8, buf, len)
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->sec_type, sec_type, UUID_SIZE);
+               memcpy(__entry->fru_id, fru_id, UUID_SIZE);
+               __assign_str(fru_text, fru_text);
+               __entry->sev = sev;
+               __entry->len = len;
+               memcpy(__get_dynamic_array(buf), err, len);
+       ),
+
+       TP_printk("severity: %d; sec type:%pU; FRU: %pU %s; data len:%d; raw data:%s",
+                 __entry->sev, __entry->sec_type,
+                 __entry->fru_id, __get_str(fru_text),
+                 __entry->len,
+                 __print_hex(__get_dynamic_array(buf), __entry->len))
+);
+
 /*
  * PCIe AER Trace event
  *