aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-06-22 21:48:30 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-05-10 10:44:48 -0400
commit854d3349973a7c47bd989794037f526b74af20c4 (patch)
tree2170050ff33e94bb481f2bdab086c3e6c1ac9a7b /drivers/edac
parent7dd6953c5fecc44d264710e1fa158d0038215b63 (diff)
i7core_edac: Get more info about the memory DIMMs
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/i7core_edac.c170
1 files changed, 107 insertions, 63 deletions
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index a6e798349e93..483cca2e543b 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -109,14 +109,14 @@
109 #define RANKOFFSET(x) ((x & RANKOFFSET_MASK) >> 10) 109 #define RANKOFFSET(x) ((x & RANKOFFSET_MASK) >> 10)
110 #define DIMM_PRESENT_MASK (1 << 9) 110 #define DIMM_PRESENT_MASK (1 << 9)
111 #define DIMM_PRESENT(x) (((x) & DIMM_PRESENT_MASK) >> 9) 111 #define DIMM_PRESENT(x) (((x) & DIMM_PRESENT_MASK) >> 9)
112 #define NUMBANK_MASK ((1 << 8) | (1 << 7)) 112 #define MC_DOD_NUMBANK_MASK ((1 << 8) | (1 << 7))
113 #define NUMBANK(x) (((x) & NUMBANK_MASK) >> 7) 113 #define MC_DOD_NUMBANK(x) (((x) & MC_DOD_NUMBANK_MASK) >> 7)
114 #define NUMRANK_MASK ((1 << 6) | (1 << 5)) 114 #define MC_DOD_NUMRANK_MASK ((1 << 6) | (1 << 5))
115 #define NUMRANK(x) (((x) & NUMRANK_MASK) >> 5) 115 #define MC_DOD_NUMRANK(x) (((x) & MC_DOD_NUMRANK_MASK) >> 5)
116 #define NUMROW_MASK ((1 << 4) | (1 << 3)) 116 #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3))
117 #define NUMROW(x) (((x) & NUMROW_MASK) >> 3) 117 #define MC_DOD_NUMROW(x) (((x) & MC_DOD_NUMROW_MASK) >> 3)
118 #define NUMCOL_MASK 3 118 #define MC_DOD_NUMCOL_MASK 3
119 #define NUMCOL(x) ((x) & NUMCOL_MASK) 119 #define MC_DOD_NUMCOL(x) ((x) & MC_DOD_NUMCOL_MASK)
120 120
121#define MC_RANK_PRESENT 0x7c 121#define MC_RANK_PRESENT 0x7c
122 122
@@ -268,41 +268,41 @@ static struct edac_pci_ctl_info *i7core_pci;
268#define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch)) 268#define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch))
269 269
270 /* MC_MAX_DOD read functions */ 270 /* MC_MAX_DOD read functions */
271static inline int maxnumdimms(struct i7core_pvt *pvt) 271static inline int numdimms(u32 dimms)
272{ 272{
273 return (pvt->info.max_dod & 0x3) + 1; 273 return (dimms & 0x3) + 1;
274} 274}
275 275
276static inline int maxnumrank(struct i7core_pvt *pvt) 276static inline int numrank(u32 rank)
277{ 277{
278 static int ranks[4] = { 1, 2, 4, -EINVAL }; 278 static int ranks[4] = { 1, 2, 4, -EINVAL };
279 279
280 return ranks[(pvt->info.max_dod >> 2) & 0x3]; 280 return ranks[rank & 0x3];
281} 281}
282 282
283static inline int maxnumbank(struct i7core_pvt *pvt) 283static inline int numbank(u32 bank)
284{ 284{
285 static int banks[4] = { 4, 8, 16, -EINVAL }; 285 static int banks[4] = { 4, 8, 16, -EINVAL };
286 286
287 return banks[(pvt->info.max_dod >> 4) & 0x3]; 287 return banks[bank & 0x3];
288} 288}
289 289
290static inline int maxnumrow(struct i7core_pvt *pvt) 290static inline int numrow(u32 row)
291{ 291{
292 static int rows[8] = { 292 static int rows[8] = {
293 1 << 12, 1 << 13, 1 << 14, 1 << 15, 293 1 << 12, 1 << 13, 1 << 14, 1 << 15,
294 1 << 16, -EINVAL, -EINVAL, -EINVAL, 294 1 << 16, -EINVAL, -EINVAL, -EINVAL,
295 }; 295 };
296 296
297 return rows[((pvt->info.max_dod >> 6) & 0x7)]; 297 return rows[row & 0x7];
298} 298}
299 299
300static inline int maxnumcol(struct i7core_pvt *pvt) 300static inline int numcol(u32 col)
301{ 301{
302 static int cols[8] = { 302 static int cols[8] = {
303 1 << 10, 1 << 11, 1 << 12, -EINVAL, 303 1 << 10, 1 << 11, 1 << 12, -EINVAL,
304 }; 304 };
305 return cols[((pvt->info.max_dod >> 9) & 0x3) << 12]; 305 return cols[col & 0x3];
306} 306}
307 307
308 308
@@ -359,10 +359,13 @@ static int get_dimm_config(struct mem_ctl_info *mci)
359{ 359{
360 struct i7core_pvt *pvt = mci->pvt_info; 360 struct i7core_pvt *pvt = mci->pvt_info;
361 struct csrow_info *csr; 361 struct csrow_info *csr;
362 struct pci_dev *pdev = pvt->pci_mcr[0]; 362 struct pci_dev *pdev;
363 int i, j, csrow = 0; 363 int i, j, csrow = 0;
364 enum edac_type mode; 364 enum edac_type mode;
365 enum mem_type mtype;
365 366
367 /* Get data from the MC register, function 0 */
368 pdev = pvt->pci_mcr[0];
366 if (!pdev) 369 if (!pdev)
367 return -ENODEV; 370 return -ENODEV;
368 371
@@ -388,15 +391,18 @@ static int get_dimm_config(struct mem_ctl_info *mci)
388 } 391 }
389 392
390 /* FIXME: need to handle the error codes */ 393 /* FIXME: need to handle the error codes */
391 debugf0("DOD Maximum limits: DIMMS: %d, %d-ranked, %d-banked\n", 394 debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked\n",
392 maxnumdimms(pvt), maxnumrank(pvt), maxnumbank(pvt)); 395 numdimms(pvt->info.max_dod),
393 debugf0("DOD Maximum rows x colums = 0x%x x 0x%x\n", 396 numrank(pvt->info.max_dod >> 2),
394 maxnumrow(pvt), maxnumcol(pvt)); 397 numbank(pvt->info.max_dod >> 4));
398 debugf0("DOD Max rows x colums = 0x%x x 0x%x\n",
399 numrow(pvt->info.max_dod >> 6),
400 numcol(pvt->info.max_dod >> 9));
395 401
396 debugf0("Memory channel configuration:\n"); 402 debugf0("Memory channel configuration:\n");
397 403
398 for (i = 0; i < NUM_CHANS; i++) { 404 for (i = 0; i < NUM_CHANS; i++) {
399 u32 data, value[8]; 405 u32 data, dimm_dod[3], value[8];
400 406
401 if (!CH_ACTIVE(pvt, i)) { 407 if (!CH_ACTIVE(pvt, i)) {
402 debugf0("Channel %i is not active\n", i); 408 debugf0("Channel %i is not active\n", i);
@@ -413,58 +419,96 @@ static int get_dimm_config(struct mem_ctl_info *mci)
413 419
414 pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT)? 4 : 2; 420 pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT)? 4 : 2;
415 421
422 if (data & REGISTERED_DIMM)
423 mtype = MEM_RDDR3;
424 else
425 mtype = MEM_DDR3;
426#if 0
416 if (data & THREE_DIMMS_PRESENT) 427 if (data & THREE_DIMMS_PRESENT)
417 pvt->channel[i].dimms = 3; 428 pvt->channel[i].dimms = 3;
418 else if (data & SINGLE_QUAD_RANK_PRESENT) 429 else if (data & SINGLE_QUAD_RANK_PRESENT)
419 pvt->channel[i].dimms = 1; 430 pvt->channel[i].dimms = 1;
420 else 431 else
421 pvt->channel[i].dimms = 2; 432 pvt->channel[i].dimms = 2;
433#endif
434
435 /* Devices 4-6 function 1 */
436 pci_read_config_dword(pvt->pci_ch[i][1],
437 MC_DOD_CH_DIMM0, &dimm_dod[0]);
438 pci_read_config_dword(pvt->pci_ch[i][1],
439 MC_DOD_CH_DIMM1, &dimm_dod[1]);
440 pci_read_config_dword(pvt->pci_ch[i][1],
441 MC_DOD_CH_DIMM2, &dimm_dod[2]);
422 442
423 debugf0("Ch%d phy rd%d, wr%d (0x%08x): " 443 debugf0("Ch%d phy rd%d, wr%d (0x%08x): "
424 "%d ranks, %d %cDIMMs, offset = %d\n\t" 444 "%d ranks, %cDIMMs\n",
425 "present: %i, numbank: %#x, numrank: %#x, "
426 "numrow: %#x, numcol: %#x\n",
427 i, 445 i,
428 RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), 446 RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i),
429 data, 447 data,
430 pvt->channel[i].ranks, pvt->channel[i].dimms, 448 pvt->channel[i].ranks,
431 (data & REGISTERED_DIMM)? 'R' : 'U', 449 (data & REGISTERED_DIMM)? 'R' : 'U');
432 RANKOFFSET(data),
433 DIMM_PRESENT(data),
434 NUMBANK(data), NUMRANK(data),
435 NUMROW(data), NUMCOL(data));
436
437 pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]);
438 pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]);
439 pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]);
440 pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]);
441 pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]);
442 pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]);
443 pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]);
444 pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]);
445 printk("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i);
446 for (j = 0; j < 8; j++)
447 printk("\t\t%#x\t%#x\t%#x\n",
448 (value[j] >> 27) & 0x1,
449 (value[j] >> 24) & 0x7,
450 (value[j] && ((1 << 24) - 1)));
451
452 csr = &mci->csrows[csrow];
453 csr->first_page = 0;
454 csr->last_page = 0;
455 csr->page_mask = 0;
456 csr->nr_pages = 0;
457 csr->grain = 0;
458 csr->csrow_idx = csrow;
459 csr->dtype = DEV_X8; /* FIXME: check this */
460 450
461 if (data & REGISTERED_DIMM) 451 for (j = 0; j < 3; j++) {
462 csr->mtype = MEM_RDDR3; 452 u32 banks, ranks, rows, cols;
463 else 453
464 csr->mtype = MEM_DDR3; 454 if (!DIMM_PRESENT(dimm_dod[j]))
465 csr->edac_mode = mode; 455 continue;
456
457 banks = numbank(MC_DOD_NUMBANK(dimm_dod[j]));
458 ranks = numrank(MC_DOD_NUMRANK(dimm_dod[j]));
459 rows = numrow(MC_DOD_NUMROW(dimm_dod[j]));
460 cols = numcol(MC_DOD_NUMCOL(dimm_dod[j]));
461
462 pvt->channel[i].dimms++;
463
464 debugf0("\tdimm %d offset: %x, numbank: %#x, "
465 "numrank: %#x, numrow: %#x, numcol: %#x\n",
466 j,
467 RANKOFFSET(dimm_dod[j]),
468 banks, ranks, rows, cols);
469
470 csr = &mci->csrows[csrow];
471 csr->first_page = 0;
472 csr->last_page = 0;
473 csr->page_mask = 0;
474 csr->nr_pages = 0;
475 csr->grain = 0;
476 csr->csrow_idx = csrow;
477
478 switch (banks) {
479 case 4:
480 csr->dtype = DEV_X4;
481 break;
482 case 8:
483 csr->dtype = DEV_X8;
484 break;
485 case 16:
486 csr->dtype = DEV_X16;
487 break;
488 default:
489 csr->dtype = DEV_UNKNOWN;
490 }
491
492 csr->edac_mode = mode;
493 csr->mtype = mtype;
494
495 csrow++;
496 }
466 497
467 csrow++; 498 pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]);
499 pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]);
500 pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]);
501 pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]);
502 pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]);
503 pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]);
504 pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]);
505 pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]);
506 printk("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i);
507 for (j = 0; j < 8; j++)
508 printk("\t\t%#x\t%#x\t%#x\n",
509 (value[j] >> 27) & 0x1,
510 (value[j] >> 24) & 0x7,
511 (value[j] && ((1 << 24) - 1)));
468 } 512 }
469 513
470 return 0; 514 return 0;