summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/edac/i7300_edac.c63
1 files changed, 51 insertions, 12 deletions
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index e33c990..a06db65 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -277,6 +277,17 @@ static const char *ferr_global_lo_name[] = {
#define NRECMEMB_CAS(v) (((v) >> 16) & 0x1fff)
#define NRECMEMB_RAS(v) ((v) & 0xffff)
+#define REDMEMA 0xdc
+
+#define RECMEMA 0xe0
+ #define RECMEMA_BANK(v) (((v) >> 12) & 7)
+ #define RECMEMA_RANK(v) (((v) >> 8) & 15)
+
+#define RECMEMB 0xe4
+ #define RECMEMB_IS_WR(v) ((v) & (1 << 31))
+ #define RECMEMB_CAS(v) (((v) >> 16) & 0x1fff)
+ #define RECMEMB_RAS(v) ((v) & 0xffff)
+
/* Device name and register DID (Device ID) */
struct i7300_dev_info {
@@ -403,10 +414,12 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
struct i7300_pvt *pvt;
u32 errnum, value;
u16 val16;
- int branch, bank, rank, cas, ras;
+ unsigned branch, bank, rank, cas, ras;
+ u32 syndrome;
+
unsigned long errors;
const char *specific;
- bool is_fatal, is_wr;
+ bool is_wr;
pvt = mci->pvt_info;
@@ -418,7 +431,6 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
errnum = find_first_bit(&errors,
ARRAY_SIZE(ferr_fat_fbd_name));
specific = GET_ERR_FROM_TABLE(ferr_fat_fbd_name, errnum);
- is_fatal = 1;
branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0;
pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map,
@@ -436,7 +448,7 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
"FATAL (Branch=%d DRAM-Bank=%d %s "
"RAS=%d CAS=%d Err=0x%lx (%s))",
- branch >> 1, bank,
+ branch, bank,
is_wr ? "RDWR" : "RD",
ras, cas,
errors, specific);
@@ -445,7 +457,6 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
edac_mc_handle_fbd_ue(mci, rank, branch << 1,
(branch << 1) + 1,
pvt->tmp_prt_buffer);
- return;
}
/* read in the 1st NON-FATAL error register */
@@ -456,20 +467,48 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
errnum = find_first_bit(&errors,
ARRAY_SIZE(ferr_nf_fbd_name));
specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum);
- is_fatal = 0;
/* Clear the error bit */
pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
FERR_GLOBAL_LO, value);
- goto error_fbd;
- }
- return;
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ REDMEMA, &syndrome);
-error_fbd:
+ branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0;
+ pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map,
+ RECMEMA, &val16);
+ bank = RECMEMA_BANK(val16);
+ rank = RECMEMA_RANK(val16);
- i7300_mc_printk(mci, KERN_EMERG, "%s FBD error on branch %d: %s\n",
- is_fatal ? "Fatal" : "NOT fatal", branch, specific);
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ RECMEMB, &value);
+
+ is_wr = RECMEMB_IS_WR(value);
+ cas = RECMEMB_CAS(value);
+ ras = RECMEMB_RAS(value);
+
+ /* Form out message */
+ snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
+ "Corrected error (Branch=%d (channel %d or %d), "
+ " DRAM-Bank=%d %s "
+ "RAS=%d CAS=%d, CE Err=0x%lx, Syndrome=0x%08x(%s))",
+ branch, branch << 1, (branch << 1) + 1,
+ bank,
+ is_wr ? "RDWR" : "RD",
+ ras, cas,
+ errors, syndrome, specific);
+
+ /*
+ * Call the helper to output message
+ * NOTE: Errors are reported per-branch, and not per-channel
+ * Currently, we don't know how to identify the right
+ * channel.
+ */
+ edac_mc_handle_fbd_ce(mci, rank, branch << 1,
+ pvt->tmp_prt_buffer);
+ }
+ return;
}
/*
OpenPOWER on IntegriCloud