diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-02-15 04:36:27 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-02-25 17:42:13 -0500 |
commit | f04c62a7036a4b8490b224a9ad1be4378a3acf4d (patch) | |
tree | 7e2105ce31e32b1de8887a91c829cee76654e1d0 /drivers/edac | |
parent | 77c5f5d2f212e1963063e427fc57c44bf6eae9fb (diff) |
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')
-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); | |||
27 | static int ghes_edac_mc_num; | 27 | static int ghes_edac_mc_num; |
28 | 28 | ||
29 | void ghes_edac_report_mem_error(struct ghes *ghes, int sev, | 29 | void ghes_edac_report_mem_error(struct ghes *ghes, int sev, |
30 | struct cper_sec_mem_err *mem_err) | 30 | struct cper_sec_mem_err *mem_err) |
31 | { | 31 | { |
32 | enum hw_event_mc_err_type type; | ||
33 | struct edac_raw_error_desc *e; | ||
34 | struct mem_ctl_info *mci; | ||
35 | struct ghes_edac_pvt *pvt = NULL; | ||
36 | |||
37 | list_for_each_entry(pvt, &ghes_reglist, list) { | ||
38 | if (ghes == pvt->ghes) | ||
39 | break; | ||
40 | } | ||
41 | if (!pvt) { | ||
42 | pr_err("Internal error: Can't find EDAC structure\n"); | ||
43 | return; | ||
44 | } | ||
45 | mci = pvt->mci; | ||
46 | e = &mci->error_desc; | ||
47 | |||
48 | /* Cleans the error report buffer */ | ||
49 | memset(e, 0, sizeof (*e)); | ||
50 | e->error_count = 1; | ||
51 | e->msg = "APEI"; | ||
52 | strcpy(e->label, "unknown"); | ||
53 | e->other_detail = ""; | ||
54 | |||
55 | if (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) { | ||
56 | e->page_frame_number = mem_err->physical_addr >> PAGE_SHIFT; | ||
57 | e->offset_in_page = mem_err->physical_addr & ~PAGE_MASK; | ||
58 | e->grain = ~(mem_err->physical_addr_mask & ~PAGE_MASK); | ||
59 | } | ||
60 | |||
61 | switch (sev) { | ||
62 | case GHES_SEV_CORRECTED: | ||
63 | type = HW_EVENT_ERR_CORRECTED; | ||
64 | break; | ||
65 | case GHES_SEV_RECOVERABLE: | ||
66 | type = HW_EVENT_ERR_UNCORRECTED; | ||
67 | break; | ||
68 | case GHES_SEV_PANIC: | ||
69 | type = HW_EVENT_ERR_FATAL; | ||
70 | break; | ||
71 | default: | ||
72 | case GHES_SEV_NO: | ||
73 | type = HW_EVENT_ERR_INFO; | ||
74 | } | ||
75 | |||
76 | sprintf(e->location, | ||
77 | "node:%d card:%d module:%d bank:%d device:%d row: %d column:%d bit_pos:%d", | ||
78 | mem_err->node, mem_err->card, mem_err->module, | ||
79 | mem_err->bank, mem_err->device, mem_err->row, mem_err->column, | ||
80 | mem_err->bit_pos); | ||
81 | edac_dbg(3, "error at location %s\n", e->location); | ||
82 | |||
83 | edac_raw_mc_handle_error(type, mci, e); | ||
32 | } | 84 | } |
33 | EXPORT_SYMBOL_GPL(ghes_edac_report_mem_error); | 85 | EXPORT_SYMBOL_GPL(ghes_edac_report_mem_error); |
34 | 86 | ||
@@ -60,7 +112,7 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev) | |||
60 | 112 | ||
61 | pvt = mci->pvt_info; | 113 | pvt = mci->pvt_info; |
62 | memset(pvt, 0, sizeof(*pvt)); | 114 | memset(pvt, 0, sizeof(*pvt)); |
63 | list_add_tail(&pvt->list, &ghes_reglist); | 115 | list_add_tail(&pvt->list, &ghes_reglist); |
64 | pvt->ghes = ghes; | 116 | pvt->ghes = ghes; |
65 | pvt->mci = mci; | 117 | pvt->mci = mci; |
66 | mci->pdev = dev; | 118 | mci->pdev = dev; |