diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-06-22 21:48:30 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-10 10:44:48 -0400 |
commit | 854d3349973a7c47bd989794037f526b74af20c4 (patch) | |
tree | 2170050ff33e94bb481f2bdab086c3e6c1ac9a7b /drivers/edac | |
parent | 7dd6953c5fecc44d264710e1fa158d0038215b63 (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.c | 170 |
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 */ |
271 | static inline int maxnumdimms(struct i7core_pvt *pvt) | 271 | static inline int numdimms(u32 dimms) |
272 | { | 272 | { |
273 | return (pvt->info.max_dod & 0x3) + 1; | 273 | return (dimms & 0x3) + 1; |
274 | } | 274 | } |
275 | 275 | ||
276 | static inline int maxnumrank(struct i7core_pvt *pvt) | 276 | static 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 | ||
283 | static inline int maxnumbank(struct i7core_pvt *pvt) | 283 | static 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 | ||
290 | static inline int maxnumrow(struct i7core_pvt *pvt) | 290 | static 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 | ||
300 | static inline int maxnumcol(struct i7core_pvt *pvt) | 300 | static 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; |