diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-02-15 06:36:27 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-02-25 19:42:13 -0300 |
commit | f04c62a7036a4b8490b224a9ad1be4378a3acf4d (patch) | |
tree | 7e2105ce31e32b1de8887a91c829cee76654e1d0 /drivers/edac/ghes_edac.c | |
parent | 77c5f5d2f212e1963063e427fc57c44bf6eae9fb (diff) | |
download | linux-stable-f04c62a7036a4b8490b224a9ad1be4378a3acf4d.tar.gz linux-stable-f04c62a7036a4b8490b224a9ad1be4378a3acf4d.tar.bz2 linux-stable-f04c62a7036a4b8490b224a9ad1be4378a3acf4d.zip |
ghes_edac: add support for reporting errors via EDAC
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>
Diffstat (limited to 'drivers/edac/ghes_edac.c')
-rw-r--r-- | drivers/edac/ghes_edac.c | 56 |
1 files changed, 54 insertions, 2 deletions
diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index d8e54b496e0f..0853f450d2c1 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c @@ -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; |