aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/i5400_edac.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2012-04-16 14:09:58 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-05-28 18:11:02 -0400
commit296da591ea1d81b8d94d6e79b6c235bb820526b9 (patch)
tree9cc0f5103ee665de3845e254da353bb62cf96836 /drivers/edac/i5400_edac.c
parentd1afaa0a6e578964eeb48a3ab207072293367041 (diff)
i5400_edac: convert driver to use the new edac ABI
The legacy edac ABI is going to be removed. Port the driver to use and benefit from the new API functionality. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/edac/i5400_edac.c')
-rw-r--r--drivers/edac/i5400_edac.c217
1 files changed, 119 insertions, 98 deletions
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index 6543f4a8367b..508f369b1f6c 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
@@ -18,6 +18,10 @@
18 * Intel 5400 Chipset Memory Controller Hub (MCH) - Datasheet 18 * Intel 5400 Chipset Memory Controller Hub (MCH) - Datasheet
19 * http://developer.intel.com/design/chipsets/datashts/313070.htm 19 * http://developer.intel.com/design/chipsets/datashts/313070.htm
20 * 20 *
21 * This Memory Controller manages DDR2 FB-DIMMs. It has 2 branches, each with
22 * 2 channels operating in lockstep no-mirror mode. Each channel can have up to
23 * 4 dimm's, each with up to 8GB.
24 *
21 */ 25 */
22 26
23#include <linux/module.h> 27#include <linux/module.h>
@@ -44,12 +48,10 @@
44 edac_mc_chipset_printk(mci, level, "i5400", fmt, ##arg) 48 edac_mc_chipset_printk(mci, level, "i5400", fmt, ##arg)
45 49
46/* Limits for i5400 */ 50/* Limits for i5400 */
47#define NUM_MTRS_PER_BRANCH 4 51#define MAX_BRANCHES 2
48#define CHANNELS_PER_BRANCH 2 52#define CHANNELS_PER_BRANCH 2
49#define MAX_DIMMS_PER_CHANNEL NUM_MTRS_PER_BRANCH 53#define DIMMS_PER_CHANNEL 4
50#define MAX_CHANNELS 4 54#define MAX_CHANNELS (MAX_BRANCHES * CHANNELS_PER_BRANCH)
51/* max possible csrows per channel */
52#define MAX_CSROWS (MAX_DIMMS_PER_CHANNEL)
53 55
54/* Device 16, 56/* Device 16,
55 * Function 0: System Address 57 * Function 0: System Address
@@ -347,16 +349,16 @@ struct i5400_pvt {
347 349
348 u16 mir0, mir1; 350 u16 mir0, mir1;
349 351
350 u16 b0_mtr[NUM_MTRS_PER_BRANCH]; /* Memory Technlogy Reg */ 352 u16 b0_mtr[DIMMS_PER_CHANNEL]; /* Memory Technlogy Reg */
351 u16 b0_ambpresent0; /* Branch 0, Channel 0 */ 353 u16 b0_ambpresent0; /* Branch 0, Channel 0 */
352 u16 b0_ambpresent1; /* Brnach 0, Channel 1 */ 354 u16 b0_ambpresent1; /* Brnach 0, Channel 1 */
353 355
354 u16 b1_mtr[NUM_MTRS_PER_BRANCH]; /* Memory Technlogy Reg */ 356 u16 b1_mtr[DIMMS_PER_CHANNEL]; /* Memory Technlogy Reg */
355 u16 b1_ambpresent0; /* Branch 1, Channel 8 */ 357 u16 b1_ambpresent0; /* Branch 1, Channel 8 */
356 u16 b1_ambpresent1; /* Branch 1, Channel 1 */ 358 u16 b1_ambpresent1; /* Branch 1, Channel 1 */
357 359
358 /* DIMM information matrix, allocating architecture maximums */ 360 /* DIMM information matrix, allocating architecture maximums */
359 struct i5400_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS]; 361 struct i5400_dimm_info dimm_info[DIMMS_PER_CHANNEL][MAX_CHANNELS];
360 362
361 /* Actual values for this controller */ 363 /* Actual values for this controller */
362 int maxch; /* Max channels */ 364 int maxch; /* Max channels */
@@ -532,13 +534,15 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
532 int ras, cas; 534 int ras, cas;
533 int errnum; 535 int errnum;
534 char *type = NULL; 536 char *type = NULL;
537 enum hw_event_mc_err_type tp_event = HW_EVENT_ERR_UNCORRECTED;
535 538
536 if (!allErrors) 539 if (!allErrors)
537 return; /* if no error, return now */ 540 return; /* if no error, return now */
538 541
539 if (allErrors & ERROR_FAT_MASK) 542 if (allErrors & ERROR_FAT_MASK) {
540 type = "FATAL"; 543 type = "FATAL";
541 else if (allErrors & FERR_NF_UNCORRECTABLE) 544 tp_event = HW_EVENT_ERR_FATAL;
545 } else if (allErrors & FERR_NF_UNCORRECTABLE)
542 type = "NON-FATAL uncorrected"; 546 type = "NON-FATAL uncorrected";
543 else 547 else
544 type = "NON-FATAL recoverable"; 548 type = "NON-FATAL recoverable";
@@ -556,7 +560,7 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
556 ras = nrec_ras(info); 560 ras = nrec_ras(info);
557 cas = nrec_cas(info); 561 cas = nrec_cas(info);
558 562
559 debugf0("\t\tCSROW= %d Channels= %d,%d (Branch= %d " 563 debugf0("\t\tDIMM= %d Channels= %d,%d (Branch= %d "
560 "DRAM Bank= %d Buffer ID = %d rdwr= %s ras= %d cas= %d)\n", 564 "DRAM Bank= %d Buffer ID = %d rdwr= %s ras= %d cas= %d)\n",
561 rank, channel, channel + 1, branch >> 1, bank, 565 rank, channel, channel + 1, branch >> 1, bank,
562 buf_id, rdwr_str(rdwr), ras, cas); 566 buf_id, rdwr_str(rdwr), ras, cas);
@@ -566,13 +570,13 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
566 570
567 /* Form out message */ 571 /* Form out message */
568 snprintf(msg, sizeof(msg), 572 snprintf(msg, sizeof(msg),
569 "%s (Branch=%d DRAM-Bank=%d Buffer ID = %d RDWR=%s " 573 "Bank=%d Buffer ID = %d RAS=%d CAS=%d Err=0x%lx (%s)",
570 "RAS=%d CAS=%d %s Err=0x%lx (%s))", 574 bank, buf_id, ras, cas, allErrors, error_name[errnum]);
571 type, branch >> 1, bank, buf_id, rdwr_str(rdwr), ras, cas,
572 type, allErrors, error_name[errnum]);
573 575
574 /* Call the helper to output message */ 576 edac_mc_handle_error(tp_event, mci, 0, 0, 0,
575 edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); 577 branch >> 1, -1, rank,
578 rdwr ? "Write error" : "Read error",
579 msg, NULL);
576} 580}
577 581
578/* 582/*
@@ -630,7 +634,7 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci,
630 /* Only 1 bit will be on */ 634 /* Only 1 bit will be on */
631 errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name)); 635 errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name));
632 636
633 debugf0("\t\tCSROW= %d Channel= %d (Branch %d " 637 debugf0("\t\tDIMM= %d Channel= %d (Branch %d "
634 "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n", 638 "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
635 rank, channel, branch >> 1, bank, 639 rank, channel, branch >> 1, bank,
636 rdwr_str(rdwr), ras, cas); 640 rdwr_str(rdwr), ras, cas);
@@ -642,8 +646,10 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci,
642 branch >> 1, bank, rdwr_str(rdwr), ras, cas, 646 branch >> 1, bank, rdwr_str(rdwr), ras, cas,
643 allErrors, error_name[errnum]); 647 allErrors, error_name[errnum]);
644 648
645 /* Call the helper to output message */ 649 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
646 edac_mc_handle_fbd_ce(mci, rank, channel, msg); 650 branch >> 1, channel % 2, rank,
651 rdwr ? "Write error" : "Read error",
652 msg, NULL);
647 653
648 return; 654 return;
649 } 655 }
@@ -831,8 +837,8 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
831/* 837/*
832 * determine_amb_present 838 * determine_amb_present
833 * 839 *
834 * the information is contained in NUM_MTRS_PER_BRANCH different 840 * the information is contained in DIMMS_PER_CHANNEL different
835 * registers determining which of the NUM_MTRS_PER_BRANCH requires 841 * registers determining which of the DIMMS_PER_CHANNEL requires
836 * knowing which channel is in question 842 * knowing which channel is in question
837 * 843 *
838 * 2 branches, each with 2 channels 844 * 2 branches, each with 2 channels
@@ -861,11 +867,11 @@ static int determine_amb_present_reg(struct i5400_pvt *pvt, int channel)
861} 867}
862 868
863/* 869/*
864 * determine_mtr(pvt, csrow, channel) 870 * determine_mtr(pvt, dimm, channel)
865 * 871 *
866 * return the proper MTR register as determine by the csrow and desired channel 872 * return the proper MTR register as determine by the dimm and desired channel
867 */ 873 */
868static int determine_mtr(struct i5400_pvt *pvt, int csrow, int channel) 874static int determine_mtr(struct i5400_pvt *pvt, int dimm, int channel)
869{ 875{
870 int mtr; 876 int mtr;
871 int n; 877 int n;
@@ -873,11 +879,11 @@ static int determine_mtr(struct i5400_pvt *pvt, int csrow, int channel)
873 /* There is one MTR for each slot pair of FB-DIMMs, 879 /* There is one MTR for each slot pair of FB-DIMMs,
874 Each slot pair may be at branch 0 or branch 1. 880 Each slot pair may be at branch 0 or branch 1.
875 */ 881 */
876 n = csrow; 882 n = dimm;
877 883
878 if (n >= NUM_MTRS_PER_BRANCH) { 884 if (n >= DIMMS_PER_CHANNEL) {
879 debugf0("ERROR: trying to access an invalid csrow: %d\n", 885 debugf0("ERROR: trying to access an invalid dimm: %d\n",
880 csrow); 886 dimm);
881 return 0; 887 return 0;
882 } 888 }
883 889
@@ -913,19 +919,19 @@ static void decode_mtr(int slot_row, u16 mtr)
913 debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]); 919 debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
914} 920}
915 921
916static void handle_channel(struct i5400_pvt *pvt, int csrow, int channel, 922static void handle_channel(struct i5400_pvt *pvt, int dimm, int channel,
917 struct i5400_dimm_info *dinfo) 923 struct i5400_dimm_info *dinfo)
918{ 924{
919 int mtr; 925 int mtr;
920 int amb_present_reg; 926 int amb_present_reg;
921 int addrBits; 927 int addrBits;
922 928
923 mtr = determine_mtr(pvt, csrow, channel); 929 mtr = determine_mtr(pvt, dimm, channel);
924 if (MTR_DIMMS_PRESENT(mtr)) { 930 if (MTR_DIMMS_PRESENT(mtr)) {
925 amb_present_reg = determine_amb_present_reg(pvt, channel); 931 amb_present_reg = determine_amb_present_reg(pvt, channel);
926 932
927 /* Determine if there is a DIMM present in this DIMM slot */ 933 /* Determine if there is a DIMM present in this DIMM slot */
928 if (amb_present_reg & (1 << csrow)) { 934 if (amb_present_reg & (1 << dimm)) {
929 /* Start with the number of bits for a Bank 935 /* Start with the number of bits for a Bank
930 * on the DRAM */ 936 * on the DRAM */
931 addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr); 937 addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr);
@@ -954,7 +960,7 @@ static void handle_channel(struct i5400_pvt *pvt, int csrow, int channel,
954static void calculate_dimm_size(struct i5400_pvt *pvt) 960static void calculate_dimm_size(struct i5400_pvt *pvt)
955{ 961{
956 struct i5400_dimm_info *dinfo; 962 struct i5400_dimm_info *dinfo;
957 int csrow, max_csrows; 963 int dimm, max_dimms;
958 char *p, *mem_buffer; 964 char *p, *mem_buffer;
959 int space, n; 965 int space, n;
960 int channel; 966 int channel;
@@ -968,32 +974,32 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
968 return; 974 return;
969 } 975 }
970 976
971 /* Scan all the actual CSROWS 977 /* Scan all the actual DIMMS
972 * and calculate the information for each DIMM 978 * and calculate the information for each DIMM
973 * Start with the highest csrow first, to display it first 979 * Start with the highest dimm first, to display it first
974 * and work toward the 0th csrow 980 * and work toward the 0th dimm
975 */ 981 */
976 max_csrows = pvt->maxdimmperch; 982 max_dimms = pvt->maxdimmperch;
977 for (csrow = max_csrows - 1; csrow >= 0; csrow--) { 983 for (dimm = max_dimms - 1; dimm >= 0; dimm--) {
978 984
979 /* on an odd csrow, first output a 'boundary' marker, 985 /* on an odd dimm, first output a 'boundary' marker,
980 * then reset the message buffer */ 986 * then reset the message buffer */
981 if (csrow & 0x1) { 987 if (dimm & 0x1) {
982 n = snprintf(p, space, "---------------------------" 988 n = snprintf(p, space, "---------------------------"
983 "--------------------------------"); 989 "-------------------------------");
984 p += n; 990 p += n;
985 space -= n; 991 space -= n;
986 debugf2("%s\n", mem_buffer); 992 debugf2("%s\n", mem_buffer);
987 p = mem_buffer; 993 p = mem_buffer;
988 space = PAGE_SIZE; 994 space = PAGE_SIZE;
989 } 995 }
990 n = snprintf(p, space, "csrow %2d ", csrow); 996 n = snprintf(p, space, "dimm %2d ", dimm);
991 p += n; 997 p += n;
992 space -= n; 998 space -= n;
993 999
994 for (channel = 0; channel < pvt->maxch; channel++) { 1000 for (channel = 0; channel < pvt->maxch; channel++) {
995 dinfo = &pvt->dimm_info[csrow][channel]; 1001 dinfo = &pvt->dimm_info[dimm][channel];
996 handle_channel(pvt, csrow, channel, dinfo); 1002 handle_channel(pvt, dimm, channel, dinfo);
997 n = snprintf(p, space, "%4d MB | ", dinfo->megabytes); 1003 n = snprintf(p, space, "%4d MB | ", dinfo->megabytes);
998 p += n; 1004 p += n;
999 space -= n; 1005 space -= n;
@@ -1005,7 +1011,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
1005 1011
1006 /* Output the last bottom 'boundary' marker */ 1012 /* Output the last bottom 'boundary' marker */
1007 n = snprintf(p, space, "---------------------------" 1013 n = snprintf(p, space, "---------------------------"
1008 "--------------------------------"); 1014 "-------------------------------");
1009 p += n; 1015 p += n;
1010 space -= n; 1016 space -= n;
1011 debugf2("%s\n", mem_buffer); 1017 debugf2("%s\n", mem_buffer);
@@ -1013,7 +1019,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
1013 space = PAGE_SIZE; 1019 space = PAGE_SIZE;
1014 1020
1015 /* now output the 'channel' labels */ 1021 /* now output the 'channel' labels */
1016 n = snprintf(p, space, " "); 1022 n = snprintf(p, space, " ");
1017 p += n; 1023 p += n;
1018 space -= n; 1024 space -= n;
1019 for (channel = 0; channel < pvt->maxch; channel++) { 1025 for (channel = 0; channel < pvt->maxch; channel++) {
@@ -1080,7 +1086,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
1080 debugf2("MIR1: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0); 1086 debugf2("MIR1: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0);
1081 1087
1082 /* Get the set of MTR[0-3] regs by each branch */ 1088 /* Get the set of MTR[0-3] regs by each branch */
1083 for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++) { 1089 for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++) {
1084 int where = MTR0 + (slot_row * sizeof(u16)); 1090 int where = MTR0 + (slot_row * sizeof(u16));
1085 1091
1086 /* Branch 0 set of MTR registers */ 1092 /* Branch 0 set of MTR registers */
@@ -1105,7 +1111,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
1105 /* Read and dump branch 0's MTRs */ 1111 /* Read and dump branch 0's MTRs */
1106 debugf2("\nMemory Technology Registers:\n"); 1112 debugf2("\nMemory Technology Registers:\n");
1107 debugf2(" Branch 0:\n"); 1113 debugf2(" Branch 0:\n");
1108 for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++) 1114 for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++)
1109 decode_mtr(slot_row, pvt->b0_mtr[slot_row]); 1115 decode_mtr(slot_row, pvt->b0_mtr[slot_row]);
1110 1116
1111 pci_read_config_word(pvt->branch_0, AMBPRESENT_0, 1117 pci_read_config_word(pvt->branch_0, AMBPRESENT_0,
@@ -1122,7 +1128,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
1122 } else { 1128 } else {
1123 /* Read and dump branch 1's MTRs */ 1129 /* Read and dump branch 1's MTRs */
1124 debugf2(" Branch 1:\n"); 1130 debugf2(" Branch 1:\n");
1125 for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++) 1131 for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++)
1126 decode_mtr(slot_row, pvt->b1_mtr[slot_row]); 1132 decode_mtr(slot_row, pvt->b1_mtr[slot_row]);
1127 1133
1128 pci_read_config_word(pvt->branch_1, AMBPRESENT_0, 1134 pci_read_config_word(pvt->branch_1, AMBPRESENT_0,
@@ -1141,7 +1147,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
1141} 1147}
1142 1148
1143/* 1149/*
1144 * i5400_init_csrows Initialize the 'csrows' table within 1150 * i5400_init_dimms Initialize the 'dimms' table within
1145 * the mci control structure with the 1151 * the mci control structure with the
1146 * addressing of memory. 1152 * addressing of memory.
1147 * 1153 *
@@ -1149,50 +1155,68 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
1149 * 0 success 1155 * 0 success
1150 * 1 no actual memory found on this MC 1156 * 1 no actual memory found on this MC
1151 */ 1157 */
1152static int i5400_init_csrows(struct mem_ctl_info *mci) 1158static int i5400_init_dimms(struct mem_ctl_info *mci)
1153{ 1159{
1154 struct i5400_pvt *pvt; 1160 struct i5400_pvt *pvt;
1155 struct csrow_info *p_csrow; 1161 struct dimm_info *dimm;
1156 int empty, channel_count; 1162 int ndimms, channel_count;
1157 int max_csrows; 1163 int max_dimms;
1158 int mtr; 1164 int mtr;
1159 int size_mb; 1165 int size_mb;
1160 int channel; 1166 int channel, slot;
1161 int csrow;
1162 struct dimm_info *dimm;
1163 1167
1164 pvt = mci->pvt_info; 1168 pvt = mci->pvt_info;
1165 1169
1166 channel_count = pvt->maxch; 1170 channel_count = pvt->maxch;
1167 max_csrows = pvt->maxdimmperch; 1171 max_dimms = pvt->maxdimmperch;
1168 1172
1169 empty = 1; /* Assume NO memory */ 1173 ndimms = 0;
1170 1174
1171 for (csrow = 0; csrow < max_csrows; csrow++) { 1175 /*
1172 p_csrow = &mci->csrows[csrow]; 1176 * FIXME: remove pvt->dimm_info[slot][channel] and use the 3
1177 * layers here.
1178 */
1179 for (channel = 0; channel < mci->layers[0].size * mci->layers[1].size;
1180 channel++) {
1181 for (slot = 0; slot < mci->layers[2].size; slot++) {
1182 mtr = determine_mtr(pvt, slot, channel);
1173 1183
1174 /* use branch 0 for the basis */ 1184 /* if no DIMMS on this slot, continue */
1175 mtr = determine_mtr(pvt, csrow, 0); 1185 if (!MTR_DIMMS_PRESENT(mtr))
1186 continue;
1176 1187
1177 /* if no DIMMS on this row, continue */ 1188 dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
1178 if (!MTR_DIMMS_PRESENT(mtr)) 1189 channel / 2, channel % 2, slot);
1179 continue;
1180 1190
1181 for (channel = 0; channel < pvt->maxch; channel++) { 1191 size_mb = pvt->dimm_info[slot][channel].megabytes;
1182 size_mb = pvt->dimm_info[csrow][channel].megabytes; 1192
1193 debugf2("%s: dimm%zd (branch %d channel %d slot %d): %d.%03d GB\n",
1194 __func__, dimm - mci->dimms,
1195 channel / 2, channel % 2, slot,
1196 size_mb / 1000, size_mb % 1000);
1183 1197
1184 dimm = p_csrow->channels[channel].dimm;
1185 dimm->nr_pages = size_mb << 8; 1198 dimm->nr_pages = size_mb << 8;
1186 dimm->grain = 8; 1199 dimm->grain = 8;
1187 dimm->dtype = MTR_DRAM_WIDTH(mtr) ? DEV_X8 : DEV_X4; 1200 dimm->dtype = MTR_DRAM_WIDTH(mtr) ? DEV_X8 : DEV_X4;
1188 dimm->mtype = MEM_RDDR2; 1201 dimm->mtype = MEM_FB_DDR2;
1189 dimm->edac_mode = EDAC_SECDED; 1202 /*
1203 * The eccc mechanism is SDDC (aka SECC), with
1204 * is similar to Chipkill.
1205 */
1206 dimm->edac_mode = MTR_DRAM_WIDTH(mtr) ?
1207 EDAC_S8ECD8ED : EDAC_S4ECD4ED;
1208 ndimms++;
1190 } 1209 }
1191
1192 empty = 0;
1193 } 1210 }
1194 1211
1195 return empty; 1212 /*
1213 * When just one memory is provided, it should be at location (0,0,0).
1214 * With such single-DIMM mode, the SDCC algorithm degrades to SECDEC+.
1215 */
1216 if (ndimms == 1)
1217 mci->dimms[0].edac_mode = EDAC_SECDED;
1218
1219 return (ndimms == 0);
1196} 1220}
1197 1221
1198/* 1222/*
@@ -1228,9 +1252,7 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
1228{ 1252{
1229 struct mem_ctl_info *mci; 1253 struct mem_ctl_info *mci;
1230 struct i5400_pvt *pvt; 1254 struct i5400_pvt *pvt;
1231 int num_channels; 1255 struct edac_mc_layer layers[3];
1232 int num_dimms_per_channel;
1233 int num_csrows;
1234 1256
1235 if (dev_idx >= ARRAY_SIZE(i5400_devs)) 1257 if (dev_idx >= ARRAY_SIZE(i5400_devs))
1236 return -EINVAL; 1258 return -EINVAL;
@@ -1244,22 +1266,21 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
1244 if (PCI_FUNC(pdev->devfn) != 0) 1266 if (PCI_FUNC(pdev->devfn) != 0)
1245 return -ENODEV; 1267 return -ENODEV;
1246 1268
1247 /* As we don't have a motherboard identification routine to determine 1269 /*
1248 * actual number of slots/dimms per channel, we thus utilize the 1270 * allocate a new MC control structure
1249 * resource as specified by the chipset. Thus, we might have 1271 *
1250 * have more DIMMs per channel than actually on the mobo, but this 1272 * This drivers uses the DIMM slot as "csrow" and the rest as "channel".
1251 * allows the driver to support up to the chipset max, without
1252 * some fancy mobo determination.
1253 */ 1273 */
1254 num_dimms_per_channel = MAX_DIMMS_PER_CHANNEL; 1274 layers[0].type = EDAC_MC_LAYER_BRANCH;
1255 num_channels = MAX_CHANNELS; 1275 layers[0].size = MAX_BRANCHES;
1256 num_csrows = num_dimms_per_channel; 1276 layers[0].is_virt_csrow = false;
1257 1277 layers[1].type = EDAC_MC_LAYER_CHANNEL;
1258 debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n", 1278 layers[1].size = CHANNELS_PER_BRANCH;
1259 __func__, num_channels, num_dimms_per_channel, num_csrows); 1279 layers[1].is_virt_csrow = false;
1260 1280 layers[2].type = EDAC_MC_LAYER_SLOT;
1261 /* allocate a new MC control structure */ 1281 layers[2].size = DIMMS_PER_CHANNEL;
1262 mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); 1282 layers[2].is_virt_csrow = true;
1283 mci = new_edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
1263 1284
1264 if (mci == NULL) 1285 if (mci == NULL)
1265 return -ENOMEM; 1286 return -ENOMEM;
@@ -1270,8 +1291,8 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
1270 1291
1271 pvt = mci->pvt_info; 1292 pvt = mci->pvt_info;
1272 pvt->system_address = pdev; /* Record this device in our private */ 1293 pvt->system_address = pdev; /* Record this device in our private */
1273 pvt->maxch = num_channels; 1294 pvt->maxch = MAX_CHANNELS;
1274 pvt->maxdimmperch = num_dimms_per_channel; 1295 pvt->maxdimmperch = DIMMS_PER_CHANNEL;
1275 1296
1276 /* 'get' the pci devices we want to reserve for our use */ 1297 /* 'get' the pci devices we want to reserve for our use */
1277 if (i5400_get_devices(mci, dev_idx)) 1298 if (i5400_get_devices(mci, dev_idx))
@@ -1293,13 +1314,13 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
1293 /* Set the function pointer to an actual operation function */ 1314 /* Set the function pointer to an actual operation function */
1294 mci->edac_check = i5400_check_error; 1315 mci->edac_check = i5400_check_error;
1295 1316
1296 /* initialize the MC control structure 'csrows' table 1317 /* initialize the MC control structure 'dimms' table
1297 * with the mapping and control information */ 1318 * with the mapping and control information */
1298 if (i5400_init_csrows(mci)) { 1319 if (i5400_init_dimms(mci)) {
1299 debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n" 1320 debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
1300 " because i5400_init_csrows() returned nonzero " 1321 " because i5400_init_dimms() returned nonzero "
1301 "value\n"); 1322 "value\n");
1302 mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */ 1323 mci->edac_cap = EDAC_FLAG_NONE; /* no dimms found */
1303 } else { 1324 } else {
1304 debugf1("MC: Enable error reporting now\n"); 1325 debugf1("MC: Enable error reporting now\n");
1305 i5400_enable_error_reporting(mci); 1326 i5400_enable_error_reporting(mci);