Merge branch 'cleanup/messages' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.git] / drivers / acpi / acpi_extlog.c
index 340d09518f8e986a56bffd4dc61291fbcb6e0b87..b3842ffc19ba20a210bec8dd8dc5f56cf9119de9 100644 (file)
 #include <linux/cper.h>
 #include <linux/ratelimit.h>
 #include <linux/edac.h>
+#include <linux/ras.h>
 #include <asm/cpu.h>
 #include <asm/mce.h>
 
 #include "apei/apei-internal.h"
+#include <ras/ras_event.h>
 
 #define EXT_ELOG_ENTRY_MASK    GENMASK_ULL(51, 0) /* elog entry address mask */
 
@@ -137,8 +139,12 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
        struct mce *mce = (struct mce *)data;
        int     bank = mce->bank;
        int     cpu = mce->extcpu;
-       struct acpi_hest_generic_status *estatus;
-       int rc;
+       struct acpi_hest_generic_status *estatus, *tmp;
+       struct acpi_hest_generic_data *gdata;
+       const uuid_le *fru_id = &NULL_UUID_LE;
+       char *fru_text = "";
+       uuid_le *sec_type;
+       static u32 err_seq;
 
        estatus = extlog_elog_entry_check(cpu, bank);
        if (estatus == NULL)
@@ -148,8 +154,29 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
        /* clear record status to enable BIOS to update it again */
        estatus->block_status = 0;
 
-       rc = print_extlog_rcd(NULL, (struct acpi_hest_generic_status *)elog_buf, cpu);
+       tmp = (struct acpi_hest_generic_status *)elog_buf;
+
+       if (!ras_userspace_consumers()) {
+               print_extlog_rcd(NULL, tmp, cpu);
+               goto out;
+       }
+
+       /* log event via trace */
+       err_seq++;
+       gdata = (struct acpi_hest_generic_data *)(tmp + 1);
+       if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
+               fru_id = (uuid_le *)gdata->fru_id;
+       if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
+               fru_text = gdata->fru_text;
+       sec_type = (uuid_le *)gdata->section_type;
+       if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
+               struct cper_sec_mem_err *mem = (void *)(gdata + 1);
+               if (gdata->error_data_length >= sizeof(*mem))
+                       trace_extlog_mem_event(mem, err_seq, fru_id, fru_text,
+                                              (u8)gdata->error_severity);
+       }
 
+out:
        return NOTIFY_STOP;
 }
 
@@ -196,19 +223,16 @@ static int __init extlog_init(void)
        u64 cap;
        int rc;
 
+       rdmsrl(MSR_IA32_MCG_CAP, cap);
+
+       if (!(cap & MCG_ELOG_P) || !extlog_get_l1addr())
+               return -ENODEV;
+
        if (get_edac_report_status() == EDAC_REPORTING_FORCE) {
                pr_warn("Not loading eMCA, error reporting force-enabled through EDAC.\n");
                return -EPERM;
        }
 
-       rc = -ENODEV;
-       rdmsrl(MSR_IA32_MCG_CAP, cap);
-       if (!(cap & MCG_ELOG_P))
-               return rc;
-
-       if (!extlog_get_l1addr())
-               return rc;
-
        rc = -EINVAL;
        /* get L1 header to fetch necessary information */
        l1_hdr_size = sizeof(struct extlog_l1_head);