From f1576d2ef7c36cae51803a33a46437dd38a873b6 Mon Sep 17 00:00:00 2001 From: Jim Snow Date: Tue, 18 Nov 2014 14:51:09 +0100 Subject: sb_edac: Fix erroneous bytes->gigabytes conversion [ Upstream commit ece9210859abb2cc0126f8adbfbbdee668d4906a ] commit 8c009100295597f23978c224aec5751a365bc965 upstream. Signed-off-by: Jim Snow Signed-off-by: Lukasz Anaczkowski Signed-off-by: Mauro Carvalho Chehab [ vlee: Backported to 3.14. Adjusted context. ] Signed-off-by: Vinson Lee Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/edac/sb_edac.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers/edac/sb_edac.c') diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index a46c4af2ac98..15697c630139 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -910,7 +910,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci) u32 reg; u64 limit, prv = 0; u64 tmp_mb; - u32 mb, kb; + u32 gb, mb; u32 rir_way; /* @@ -920,15 +920,17 @@ static void get_memory_layout(const struct mem_ctl_info *mci) pvt->tolm = pvt->info.get_tolm(pvt); tmp_mb = (1 + pvt->tolm) >> 20; - mb = div_u64_rem(tmp_mb, 1000, &kb); - edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tolm); + gb = div_u64_rem(tmp_mb, 1024, &mb); + edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", + gb, (mb*1000)/1024, (u64)pvt->tolm); /* Address range is already 45:25 */ pvt->tohm = pvt->info.get_tohm(pvt); tmp_mb = (1 + pvt->tohm) >> 20; - mb = div_u64_rem(tmp_mb, 1000, &kb); - edac_dbg(0, "TOHM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tohm); + gb = div_u64_rem(tmp_mb, 1024, &mb); + edac_dbg(0, "TOHM: %u.%03u GB (0x%016Lx)\n", + gb, (mb*1000)/1024, (u64)pvt->tohm); /* * Step 2) Get SAD range and SAD Interleave list @@ -950,11 +952,11 @@ static void get_memory_layout(const struct mem_ctl_info *mci) break; tmp_mb = (limit + 1) >> 20; - mb = div_u64_rem(tmp_mb, 1000, &kb); + gb = div_u64_rem(tmp_mb, 1024, &mb); edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n", n_sads, get_dram_attr(reg), - mb, kb, + gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, INTERLEAVE_MODE(reg) ? "8:6" : "[8:6]XOR[18:16]", reg); @@ -985,9 +987,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci) break; tmp_mb = (limit + 1) >> 20; - mb = div_u64_rem(tmp_mb, 1000, &kb); + gb = div_u64_rem(tmp_mb, 1024, &mb); edac_dbg(0, "TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n", - n_tads, mb, kb, + n_tads, gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, (u32)TAD_SOCK(reg), (u32)TAD_CH(reg), @@ -1010,10 +1012,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) tad_ch_nilv_offset[j], ®); tmp_mb = TAD_OFFSET(reg) >> 20; - mb = div_u64_rem(tmp_mb, 1000, &kb); + gb = div_u64_rem(tmp_mb, 1024, &mb); edac_dbg(0, "TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n", i, j, - mb, kb, + gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, reg); } @@ -1035,10 +1037,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) tmp_mb = pvt->info.rir_limit(reg) >> 20; rir_way = 1 << RIR_WAY(reg); - mb = div_u64_rem(tmp_mb, 1000, &kb); + gb = div_u64_rem(tmp_mb, 1024, &mb); edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n", i, j, - mb, kb, + gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, rir_way, reg); @@ -1049,10 +1051,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ®); tmp_mb = RIR_OFFSET(reg) << 6; - mb = div_u64_rem(tmp_mb, 1000, &kb); + gb = div_u64_rem(tmp_mb, 1024, &mb); edac_dbg(0, "CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n", i, j, k, - mb, kb, + gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, (u32)RIR_RNK_TGT(reg), reg); @@ -1090,7 +1092,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, u8 ch_way, sck_way, pkg, sad_ha = 0; u32 tad_offset; u32 rir_way; - u32 mb, kb; + u32 mb, gb; u64 ch_addr, offset, limit = 0, prv = 0; @@ -1359,10 +1361,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci, continue; limit = pvt->info.rir_limit(reg); - mb = div_u64_rem(limit >> 20, 1000, &kb); + gb = div_u64_rem(limit >> 20, 1024, &mb); edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n", n_rir, - mb, kb, + gb, (mb*1000)/1024, limit, 1 << RIR_WAY(reg)); if (ch_addr <= limit) -- cgit v1.2.3 From 7d974c26f1dc39573f5f6c7d65fe21892e8246d2 Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Wed, 9 Mar 2016 16:40:48 -0800 Subject: EDAC/sb_edac: Fix computation of channel address [ Upstream commit eb1af3b71f9d83e45f2fd2fd649356e98e1c582c ] Large memory Haswell-EX systems with multiple DIMMs per channel were sometimes reporting the wrong DIMM. Found three problems: 1) Debug printouts for socket and channel interleave were not interpreting the register fields correctly. The socket interleave field is a 2^X value (0=1, 1=2, 2=4, 3=8). The channel interleave is X+1 (0=1, 1=2, 2=3. 3=4). 2) Actual use of the socket interleave value didn't interpret as 2^X 3) Conversion of address to channel address was complicated, and wrong. Signed-off-by: Tony Luck Acked-by: Aristeu Rozanski Cc: Borislav Petkov Cc: Linus Torvalds Cc: Mauro Carvalho Chehab Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-edac@vger.kernel.org Cc: stable@vger.kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- drivers/edac/sb_edac.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers/edac/sb_edac.c') diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 15697c630139..b97f5f0c5c0a 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -991,8 +991,8 @@ static void get_memory_layout(const struct mem_ctl_info *mci) edac_dbg(0, "TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n", n_tads, gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, - (u32)TAD_SOCK(reg), - (u32)TAD_CH(reg), + (u32)(1 << TAD_SOCK(reg)), + (u32)TAD_CH(reg) + 1, (u32)TAD_TGT0(reg), (u32)TAD_TGT1(reg), (u32)TAD_TGT2(reg), @@ -1264,7 +1264,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, } ch_way = TAD_CH(reg) + 1; - sck_way = TAD_SOCK(reg) + 1; + sck_way = 1 << TAD_SOCK(reg); if (ch_way == 3) idx = addr >> 6; @@ -1321,7 +1321,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, n_tads, addr, limit, - (u32)TAD_SOCK(reg), + sck_way, ch_way, offset, idx, @@ -1336,18 +1336,12 @@ static int get_memory_error_data(struct mem_ctl_info *mci, offset, addr); return -EINVAL; } - addr -= offset; - /* Store the low bits [0:6] of the addr */ - ch_addr = addr & 0x7f; - /* Remove socket wayness and remove 6 bits */ - addr >>= 6; - addr = div_u64(addr, sck_xch); -#if 0 - /* Divide by channel way */ - addr = addr / ch_way; -#endif - /* Recover the last 6 bits */ - ch_addr |= addr << 6; + + ch_addr = addr - offset; + ch_addr >>= (6 + shiftup); + ch_addr /= ch_way * sck_way; + ch_addr <<= (6 + shiftup); + ch_addr |= addr & ((1 << (6 + shiftup)) - 1); /* * Step 3) Decode rank -- cgit v1.2.3 From b7c4a9d51100cf69d87b758fb8aac3c2eb7b8499 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Thu, 14 Apr 2016 10:21:52 -0700 Subject: x86 EDAC, sb_edac.c: Repair damage introduced when "fixing" channel address [ Upstream commit ff15e95c82768d589957dbb17d7eb7dba7904659 ] In commit: eb1af3b71f9d ("Fix computation of channel address") I switched the "sck_way" variable from holding the log2 value read from the h/w to instead be the actual number. Unfortunately it is needed in log2 form when used to shift the address. Tested-by: Patrick Geary Signed-off-by: Tony Luck Acked-by: Mauro Carvalho Chehab Cc: Aristeu Rozanski Cc: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-edac@vger.kernel.org Cc: stable@vger.kernel.org Fixes: eb1af3b71f9d ("Fix computation of channel address") Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- drivers/edac/sb_edac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/edac/sb_edac.c') diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index b97f5f0c5c0a..6251a0aeadcb 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -1264,7 +1264,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, } ch_way = TAD_CH(reg) + 1; - sck_way = 1 << TAD_SOCK(reg); + sck_way = TAD_SOCK(reg); if (ch_way == 3) idx = addr >> 6; @@ -1303,7 +1303,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, switch(ch_way) { case 2: case 4: - sck_xch = 1 << sck_way * (ch_way >> 1); + sck_xch = (1 << sck_way) * (ch_way >> 1); break; default: sprintf(msg, "Invalid mirror set. Can't decode addr"); @@ -1339,7 +1339,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ch_addr = addr - offset; ch_addr >>= (6 + shiftup); - ch_addr /= ch_way * sck_way; + ch_addr /= sck_xch; ch_addr <<= (6 + shiftup); ch_addr |= addr & ((1 << (6 + shiftup)) - 1); -- cgit v1.2.3 From 65c2cfa5e503d8fdca05cd6b75b78e61b4415ae4 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 29 Apr 2016 15:42:25 +0200 Subject: EDAC: i7core, sb_edac: Don't return NOTIFY_BAD from mce_decoder callback [ Upstream commit c4fc1956fa31003bfbe4f597e359d751568e2954 ] Both of these drivers can return NOTIFY_BAD, but this terminates processing other callbacks that were registered later on the chain. Since the driver did nothing to log the error it seems wrong to prevent other interested parties from seeing it. E.g. neither of them had even bothered to check the type of the error to see if it was a memory error before the return NOTIFY_BAD. Signed-off-by: Tony Luck Acked-by: Aristeu Rozanski Acked-by: Mauro Carvalho Chehab Cc: linux-edac Cc: Link: http://lkml.kernel.org/r/72937355dd92318d2630979666063f8a2853495b.1461864507.git.tony.luck@intel.com Signed-off-by: Borislav Petkov Signed-off-by: Sasha Levin --- drivers/edac/sb_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/edac/sb_edac.c') diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 6251a0aeadcb..6aa25a3aa2c7 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -2047,7 +2047,7 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val, mci = get_mci_for_node_id(mce->socketid); if (!mci) - return NOTIFY_BAD; + return NOTIFY_DONE; pvt = mci->pvt_info; /* -- cgit v1.2.3