aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/i5100_edac.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/edac/i5100_edac.c')
-rw-r--r--drivers/edac/i5100_edac.c90
1 files changed, 40 insertions, 50 deletions
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index c08e94064ef..691cd49aa16 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -14,6 +14,11 @@
14 * rows for each respective channel are laid out one after another, 14 * rows for each respective channel are laid out one after another,
15 * the first half belonging to channel 0, the second half belonging 15 * the first half belonging to channel 0, the second half belonging
16 * to channel 1. 16 * to channel 1.
17 *
18 * This driver is for DDR2 DIMMs, and it uses chip select to select among the
19 * several ranks. However, instead of showing memories as ranks, it outputs
20 * them as DIMM's. An internal table creates the association between ranks
21 * and DIMM's.
17 */ 22 */
18#include <linux/module.h> 23#include <linux/module.h>
19#include <linux/init.h> 24#include <linux/init.h>
@@ -410,14 +415,6 @@ static int i5100_csrow_to_chan(const struct mem_ctl_info *mci, int csrow)
410 return csrow / priv->ranksperchan; 415 return csrow / priv->ranksperchan;
411} 416}
412 417
413static unsigned i5100_rank_to_csrow(const struct mem_ctl_info *mci,
414 int chan, int rank)
415{
416 const struct i5100_priv *priv = mci->pvt_info;
417
418 return chan * priv->ranksperchan + rank;
419}
420
421static void i5100_handle_ce(struct mem_ctl_info *mci, 418static void i5100_handle_ce(struct mem_ctl_info *mci,
422 int chan, 419 int chan,
423 unsigned bank, 420 unsigned bank,
@@ -427,21 +424,17 @@ static void i5100_handle_ce(struct mem_ctl_info *mci,
427 unsigned ras, 424 unsigned ras,
428 const char *msg) 425 const char *msg)
429{ 426{
430 const int csrow = i5100_rank_to_csrow(mci, chan, rank); 427 char detail[80];
431 char *label = NULL;
432 428
433 if (mci->csrows[csrow].channels[0].dimm) 429 /* Form out message */
434 label = mci->csrows[csrow].channels[0].dimm->label; 430 snprintf(detail, sizeof(detail),
431 "bank %u, cas %u, ras %u\n",
432 bank, cas, ras);
435 433
436 printk(KERN_ERR 434 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
437 "CE chan %d, bank %u, rank %u, syndrome 0x%lx, " 435 0, 0, syndrome,
438 "cas %u, ras %u, csrow %u, label \"%s\": %s\n", 436 chan, rank, -1,
439 chan, bank, rank, syndrome, cas, ras, 437 msg, detail, NULL);
440 csrow, label, msg);
441
442 mci->ce_count++;
443 mci->csrows[csrow].ce_count++;
444 mci->csrows[csrow].channels[0].ce_count++;
445} 438}
446 439
447static void i5100_handle_ue(struct mem_ctl_info *mci, 440static void i5100_handle_ue(struct mem_ctl_info *mci,
@@ -453,20 +446,17 @@ static void i5100_handle_ue(struct mem_ctl_info *mci,
453 unsigned ras, 446 unsigned ras,
454 const char *msg) 447 const char *msg)
455{ 448{
456 const int csrow = i5100_rank_to_csrow(mci, chan, rank); 449 char detail[80];
457 char *label = NULL;
458
459 if (mci->csrows[csrow].channels[0].dimm)
460 label = mci->csrows[csrow].channels[0].dimm->label;
461 450
462 printk(KERN_ERR 451 /* Form out message */
463 "UE chan %d, bank %u, rank %u, syndrome 0x%lx, " 452 snprintf(detail, sizeof(detail),
464 "cas %u, ras %u, csrow %u, label \"%s\": %s\n", 453 "bank %u, cas %u, ras %u\n",
465 chan, bank, rank, syndrome, cas, ras, 454 bank, cas, ras);
466 csrow, label, msg);
467 455
468 mci->ue_count++; 456 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
469 mci->csrows[csrow].ue_count++; 457 0, 0, syndrome,
458 chan, rank, -1,
459 msg, detail, NULL);
470} 460}
471 461
472static void i5100_read_log(struct mem_ctl_info *mci, int chan, 462static void i5100_read_log(struct mem_ctl_info *mci, int chan,
@@ -843,11 +833,10 @@ static void __devinit i5100_init_interleaving(struct pci_dev *pdev,
843static void __devinit i5100_init_csrows(struct mem_ctl_info *mci) 833static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
844{ 834{
845 int i; 835 int i;
846 unsigned long total_pages = 0UL;
847 struct i5100_priv *priv = mci->pvt_info; 836 struct i5100_priv *priv = mci->pvt_info;
848 struct dimm_info *dimm;
849 837
850 for (i = 0; i < mci->nr_csrows; i++) { 838 for (i = 0; i < mci->tot_dimms; i++) {
839 struct dimm_info *dimm;
851 const unsigned long npages = i5100_npages(mci, i); 840 const unsigned long npages = i5100_npages(mci, i);
852 const unsigned chan = i5100_csrow_to_chan(mci, i); 841 const unsigned chan = i5100_csrow_to_chan(mci, i);
853 const unsigned rank = i5100_csrow_to_rank(mci, i); 842 const unsigned rank = i5100_csrow_to_rank(mci, i);
@@ -855,30 +844,23 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
855 if (!npages) 844 if (!npages)
856 continue; 845 continue;
857 846
858 /* 847 dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
859 * FIXME: these two are totally bogus -- I don't see how to 848 chan, rank, 0);
860 * map them correctly to this structure...
861 */
862 mci->csrows[i].csrow_idx = i;
863 mci->csrows[i].mci = mci;
864 mci->csrows[i].nr_channels = 1;
865 mci->csrows[i].channels[0].csrow = mci->csrows + i;
866 total_pages += npages;
867 849
868 dimm = mci->csrows[i].channels[0].dimm;
869 dimm->nr_pages = npages; 850 dimm->nr_pages = npages;
870 if (npages) { 851 if (npages) {
871 total_pages += npages;
872
873 dimm->grain = 32; 852 dimm->grain = 32;
874 dimm->dtype = (priv->mtr[chan][rank].width == 4) ? 853 dimm->dtype = (priv->mtr[chan][rank].width == 4) ?
875 DEV_X4 : DEV_X8; 854 DEV_X4 : DEV_X8;
876 dimm->mtype = MEM_RDDR2; 855 dimm->mtype = MEM_RDDR2;
877 dimm->edac_mode = EDAC_SECDED; 856 dimm->edac_mode = EDAC_SECDED;
878 snprintf(dimm->label, sizeof(dimm->label), 857 snprintf(dimm->label, sizeof(dimm->label),
879 "DIMM%u", 858 "DIMM%u",
880 i5100_rank_to_slot(mci, chan, rank)); 859 i5100_rank_to_slot(mci, chan, rank));
881 } 860 }
861
862 debugf2("dimm channel %d, rank %d, size %zd\n",
863 chan, rank, PAGES_TO_MiB(npages));
882 } 864 }
883} 865}
884 866
@@ -887,6 +869,7 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
887{ 869{
888 int rc; 870 int rc;
889 struct mem_ctl_info *mci; 871 struct mem_ctl_info *mci;
872 struct edac_mc_layer layers[2];
890 struct i5100_priv *priv; 873 struct i5100_priv *priv;
891 struct pci_dev *ch0mm, *ch1mm; 874 struct pci_dev *ch0mm, *ch1mm;
892 int ret = 0; 875 int ret = 0;
@@ -947,7 +930,14 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
947 goto bail_ch1; 930 goto bail_ch1;
948 } 931 }
949 932
950 mci = edac_mc_alloc(sizeof(*priv), ranksperch * 2, 1, 0); 933 layers[0].type = EDAC_MC_LAYER_CHANNEL;
934 layers[0].size = 2;
935 layers[0].is_virt_csrow = false;
936 layers[1].type = EDAC_MC_LAYER_SLOT;
937 layers[1].size = ranksperch;
938 layers[1].is_virt_csrow = true;
939 mci = new_edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
940 sizeof(*priv));
951 if (!mci) { 941 if (!mci) {
952 ret = -ENOMEM; 942 ret = -ENOMEM;
953 goto bail_disable_ch1; 943 goto bail_disable_ch1;