aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/i3200_edac.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2013-01-10 11:31:47 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-02-21 09:06:31 -0500
commit61734e1835867e6e38438c8365149748641e3525 (patch)
treefeed279d24fb0ca0717941acf177119a2c9c879b /drivers/edac/i3200_edac.c
parent5f466cb0257998549058c16e9d44bb74804a273d (diff)
i3200_edac: Fix the logic that detects filled memories
After running a series of tests on an HP DL320, filled with different memory sizes, it was noticed that, when filled with just one DIMM on such hardware, the driver wrongly detects twice the memory, and thinks that both channels 0 and 1 are filled. It seems to be partially caused by the BIOS and partially by the driver. The i3200_edac current logic would be working fine if the BIOS were disabling the unused second channel when just one DIMM is connected, in order to do power-saving, as recommended on this chipset's datasheet. However, the BIOS on this particular machine doesn't do it: [ 16.741421] EDAC DEBUG: how_many_channels: In dual channel mode [ 16.741424] EDAC DEBUG: how_many_channels: 2 DIMMS per channel enabled So, the driver were assuming that 2 channels are enabled (well, they are, but the second is unused). Combined with that, I found two issues at the logic that creates the EDAC data, that were failing when the two channels are not equally filled (AFAICT, that happens only when just 1 DIMM is plugged). The first one is that a 0 at DRB means that nothing is filled. The driver's logic, however, do some calculation with that. The second one is that the logic that fills the DIMM data currently assumes that both channels are equally filled. I tested the system already with the current configuration and my patch and it is now working fine. So, for a 2R single DIMM 2Gb memory at dimm slot 01 (channel 0), it is now displaying: [ 16.741406] EDAC DEBUG: i3200_get_drbs: drb[0][0] = 16, drb[1][0] = 0 [ 16.741410] EDAC DEBUG: i3200_get_drbs: drb[0][1] = 32, drb[1][1] = 0 [ 16.741413] EDAC DEBUG: i3200_get_drbs: drb[0][2] = 32, drb[1][2] = 0 [ 16.741416] EDAC DEBUG: i3200_get_drbs: drb[0][3] = 32, drb[1][3] = 0 ... [ 16.741896] EDAC DEBUG: i3200_probe1: csrow 0, channel 0, size = 1024 Mb [ 16.741899] EDAC DEBUG: i3200_probe1: csrow 1, channel 0, size = 1024 Mb and the corresponding sysfs nodes are now properly filled. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/edac/i3200_edac.c')
-rw-r--r--drivers/edac/i3200_edac.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index 20641925d313..aa44c1718f50 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -323,6 +323,9 @@ static unsigned long drb_to_nr_pages(
323 int n; 323 int n;
324 324
325 n = drbs[channel][rank]; 325 n = drbs[channel][rank];
326 if (!n)
327 return 0;
328
326 if (rank > 0) 329 if (rank > 0)
327 n -= drbs[channel][rank - 1]; 330 n -= drbs[channel][rank - 1];
328 if (stacked && (channel == 1) && 331 if (stacked && (channel == 1) &&
@@ -389,19 +392,19 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
389 * cumulative; the last one will contain the total memory 392 * cumulative; the last one will contain the total memory
390 * contained in all ranks. 393 * contained in all ranks.
391 */ 394 */
392 for (i = 0; i < mci->nr_csrows; i++) { 395 for (i = 0; i < I3200_DIMMS; i++) {
393 unsigned long nr_pages; 396 unsigned long nr_pages;
394 struct csrow_info *csrow = mci->csrows[i];
395 397
396 nr_pages = drb_to_nr_pages(drbs, stacked, 398 for (j = 0; j < nr_channels; j++) {
397 i / I3200_RANKS_PER_CHANNEL, 399 struct dimm_info *dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
398 i % I3200_RANKS_PER_CHANNEL); 400 mci->n_layers, i, j, 0);
399 401
400 if (nr_pages == 0) 402 nr_pages = drb_to_nr_pages(drbs, stacked, j, i);
401 continue; 403 if (nr_pages == 0)
404 continue;
402 405
403 for (j = 0; j < nr_channels; j++) { 406 edac_dbg(0, "csrow %d, channel %d%s, size = %ld Mb\n", i, j,
404 struct dimm_info *dimm = csrow->channels[j]->dimm; 407 stacked ? " (stacked)" : "", PAGES_TO_MiB(nr_pages));
405 408
406 dimm->nr_pages = nr_pages; 409 dimm->nr_pages = nr_pages;
407 dimm->grain = nr_pages << PAGE_SHIFT; 410 dimm->grain = nr_pages << PAGE_SHIFT;