Commit 14a7213e authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab Committed by Greg Kroah-Hartman

sb_edac: Avoid overflow errors at memory size calculation

commit deb09dda upstream.

Sandy bridge EDAC is calculating the memory size with overflow.
Basically, the size field and the integer calculation is using 32 bits.
More bits are needed, when the DIMM memories have high density.

The net result is that memories are improperly reported there, when
high-density DIMMs are used:

EDAC DEBUG: in drivers/edac/sb_edac.c, line at 591: mc#0: channel 0, dimm 0, -16384 Mb (-4194304 pages) bank: 8, rank: 2, row: 0x10000, col: 0x800
EDAC DEBUG: in drivers/edac/sb_edac.c, line at 591: mc#0: channel 1, dimm 0, -16384 Mb (-4194304 pages) bank: 8, rank: 2, row: 0x10000, col: 0x800

As the number of pages value is handled at the EDAC core as unsigned
ints, the driver shows the 16 GB memories at sysfs interface as 16760832
MB! The fix is simple: calculate the number of pages as unsigned 64-bits
integer.

After the patch, the memory size (16 GB) is properly detected:

EDAC DEBUG: in drivers/edac/sb_edac.c, line at 592: mc#0: channel 0, dimm 0, 16384 Mb (4194304 pages) bank: 8, rank: 2, row: 0x10000, col: 0x800
EDAC DEBUG: in drivers/edac/sb_edac.c, line at 592: mc#0: channel 1, dimm 0, 16384 Mb (4194304 pages) bank: 8, rank: 2, row: 0x10000, col: 0x800
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
[bwh: Backported to 3.2:
 - Adjust context
 - Debug log function is debugf0(), not edac_dbg()]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
Cc: Qiang Huang <h.huangqiang@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 82d16b39
...@@ -555,7 +555,8 @@ static int get_dimm_config(const struct mem_ctl_info *mci) ...@@ -555,7 +555,8 @@ static int get_dimm_config(const struct mem_ctl_info *mci)
{ {
struct sbridge_pvt *pvt = mci->pvt_info; struct sbridge_pvt *pvt = mci->pvt_info;
struct csrow_info *csr; struct csrow_info *csr;
int i, j, banks, ranks, rows, cols, size, npages; unsigned i, j, banks, ranks, rows, cols, npages;
u64 size;
int csrow = 0; int csrow = 0;
unsigned long last_page = 0; unsigned long last_page = 0;
u32 reg; u32 reg;
...@@ -627,10 +628,10 @@ static int get_dimm_config(const struct mem_ctl_info *mci) ...@@ -627,10 +628,10 @@ static int get_dimm_config(const struct mem_ctl_info *mci)
cols = numcol(mtr); cols = numcol(mtr);
/* DDR3 has 8 I/O banks */ /* DDR3 has 8 I/O banks */
size = (rows * cols * banks * ranks) >> (20 - 3); size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
npages = MiB_TO_PAGES(size); npages = MiB_TO_PAGES(size);
debugf0("mc#%d: channel %d, dimm %d, %d Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n", debugf0("mc#%d: channel %d, dimm %d, %Ld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
pvt->sbridge_dev->mc, i, j, pvt->sbridge_dev->mc, i, j,
size, npages, size, npages,
banks, ranks, rows, cols); banks, ranks, rows, cols);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment