ghes_edac: add support for reporting errors via EDAC
authorMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 15 Feb 2013 09:36:27 +0000 (06:36 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 25 Feb 2013 22:42:13 +0000 (19:42 -0300)
Now that the EDAC core is capable of just forward the errors via
the userspace API, add a report mechanism for the GHES errors.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/edac/ghes_edac.c

index d8e54b496e0f91655d0cc3241a07baf346543c5d..0853f450d2c102cdcefee8503e796a811c4a79f6 100644 (file)
@@ -27,8 +27,60 @@ static DEFINE_MUTEX(ghes_edac_lock);
 static int ghes_edac_mc_num;
 
 void ghes_edac_report_mem_error(struct ghes *ghes, int sev,
-                               struct cper_sec_mem_err *mem_err)
+                               struct cper_sec_mem_err *mem_err)
 {
+       enum hw_event_mc_err_type type;
+       struct edac_raw_error_desc *e;
+       struct mem_ctl_info *mci;
+       struct ghes_edac_pvt *pvt = NULL;
+
+       list_for_each_entry(pvt, &ghes_reglist, list) {
+               if (ghes == pvt->ghes)
+                       break;
+       }
+       if (!pvt) {
+               pr_err("Internal error: Can't find EDAC structure\n");
+               return;
+       }
+       mci = pvt->mci;
+       e = &mci->error_desc;
+
+       /* Cleans the error report buffer */
+       memset(e, 0, sizeof (*e));
+       e->error_count = 1;
+       e->msg = "APEI";
+       strcpy(e->label, "unknown");
+       e->other_detail = "";
+
+       if (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) {
+               e->page_frame_number = mem_err->physical_addr >> PAGE_SHIFT;
+               e->offset_in_page = mem_err->physical_addr & ~PAGE_MASK;
+               e->grain = ~(mem_err->physical_addr_mask & ~PAGE_MASK);
+       }
+
+       switch (sev) {
+       case GHES_SEV_CORRECTED:
+               type = HW_EVENT_ERR_CORRECTED;
+               break;
+       case GHES_SEV_RECOVERABLE:
+               type = HW_EVENT_ERR_UNCORRECTED;
+               break;
+       case GHES_SEV_PANIC:
+               type = HW_EVENT_ERR_FATAL;
+               break;
+       default:
+       case GHES_SEV_NO:
+               type = HW_EVENT_ERR_INFO;
+       }
+
+       sprintf(e->location,
+               "node:%d card:%d module:%d bank:%d device:%d row: %d column:%d bit_pos:%d",
+               mem_err->node, mem_err->card, mem_err->module,
+               mem_err->bank, mem_err->device, mem_err->row, mem_err->column,
+               mem_err->bit_pos);
+       edac_dbg(3, "error at location %s\n", e->location);
+
+       edac_raw_mc_handle_error(type, mci, e);
 }
 EXPORT_SYMBOL_GPL(ghes_edac_report_mem_error);
 
@@ -60,7 +112,7 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev)
 
        pvt = mci->pvt_info;
        memset(pvt, 0, sizeof(*pvt));
-        list_add_tail(&pvt->list, &ghes_reglist);
+       list_add_tail(&pvt->list, &ghes_reglist);
        pvt->ghes = ghes;
        pvt->mci  = mci;
        mci->pdev = dev;