aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/i5000_edac.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/edac/i5000_edac.c')
-rw-r--r--drivers/edac/i5000_edac.c150
1 files changed, 79 insertions, 71 deletions
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 82f3f4d2e7b8..1c1aa7a23c3c 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -270,7 +270,8 @@
270#define MTR3 0x8C 270#define MTR3 0x8C
271 271
272#define NUM_MTRS 4 272#define NUM_MTRS 4
273#define CHANNELS_PER_BRANCH (2) 273#define CHANNELS_PER_BRANCH 2
274#define MAX_BRANCHES 2
274 275
275/* Defines to extract the vaious fields from the 276/* Defines to extract the vaious fields from the
276 * MTRx - Memory Technology Registers 277 * MTRx - Memory Technology Registers
@@ -962,14 +963,14 @@ static int determine_amb_present_reg(struct i5000_pvt *pvt, int channel)
962 * 963 *
963 * return the proper MTR register as determine by the csrow and channel desired 964 * return the proper MTR register as determine by the csrow and channel desired
964 */ 965 */
965static int determine_mtr(struct i5000_pvt *pvt, int csrow, int channel) 966static int determine_mtr(struct i5000_pvt *pvt, int slot, int channel)
966{ 967{
967 int mtr; 968 int mtr;
968 969
969 if (channel < CHANNELS_PER_BRANCH) 970 if (channel < CHANNELS_PER_BRANCH)
970 mtr = pvt->b0_mtr[csrow >> 1]; 971 mtr = pvt->b0_mtr[slot];
971 else 972 else
972 mtr = pvt->b1_mtr[csrow >> 1]; 973 mtr = pvt->b1_mtr[slot];
973 974
974 return mtr; 975 return mtr;
975} 976}
@@ -994,37 +995,34 @@ static void decode_mtr(int slot_row, u16 mtr)
994 debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]); 995 debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
995} 996}
996 997
997static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel, 998static void handle_channel(struct i5000_pvt *pvt, int slot, int channel,
998 struct i5000_dimm_info *dinfo) 999 struct i5000_dimm_info *dinfo)
999{ 1000{
1000 int mtr; 1001 int mtr;
1001 int amb_present_reg; 1002 int amb_present_reg;
1002 int addrBits; 1003 int addrBits;
1003 1004
1004 mtr = determine_mtr(pvt, csrow, channel); 1005 mtr = determine_mtr(pvt, slot, channel);
1005 if (MTR_DIMMS_PRESENT(mtr)) { 1006 if (MTR_DIMMS_PRESENT(mtr)) {
1006 amb_present_reg = determine_amb_present_reg(pvt, channel); 1007 amb_present_reg = determine_amb_present_reg(pvt, channel);
1007 1008
1008 /* Determine if there is a DIMM present in this DIMM slot */ 1009 /* Determine if there is a DIMM present in this DIMM slot */
1009 if (amb_present_reg & (1 << (csrow >> 1))) { 1010 if (amb_present_reg) {
1010 dinfo->dual_rank = MTR_DIMM_RANK(mtr); 1011 dinfo->dual_rank = MTR_DIMM_RANK(mtr);
1011 1012
1012 if (!((dinfo->dual_rank == 0) && 1013 /* Start with the number of bits for a Bank
1013 ((csrow & 0x1) == 0x1))) { 1014 * on the DRAM */
1014 /* Start with the number of bits for a Bank 1015 addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr);
1015 * on the DRAM */ 1016 /* Add the number of ROW bits */
1016 addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr); 1017 addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
1017 /* Add thenumber of ROW bits */ 1018 /* add the number of COLUMN bits */
1018 addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr); 1019 addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
1019 /* add the number of COLUMN bits */ 1020
1020 addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); 1021 addrBits += 6; /* add 64 bits per DIMM */
1021 1022 addrBits -= 20; /* divide by 2^^20 */
1022 addrBits += 6; /* add 64 bits per DIMM */ 1023 addrBits -= 3; /* 8 bits per bytes */
1023 addrBits -= 20; /* divide by 2^^20 */ 1024
1024 addrBits -= 3; /* 8 bits per bytes */ 1025 dinfo->megabytes = 1 << addrBits;
1025
1026 dinfo->megabytes = 1 << addrBits;
1027 }
1028 } 1026 }
1029 } 1027 }
1030} 1028}
@@ -1038,10 +1036,9 @@ static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel,
1038static void calculate_dimm_size(struct i5000_pvt *pvt) 1036static void calculate_dimm_size(struct i5000_pvt *pvt)
1039{ 1037{
1040 struct i5000_dimm_info *dinfo; 1038 struct i5000_dimm_info *dinfo;
1041 int csrow, max_csrows; 1039 int slot, channel, branch;
1042 char *p, *mem_buffer; 1040 char *p, *mem_buffer;
1043 int space, n; 1041 int space, n;
1044 int channel;
1045 1042
1046 /* ================= Generate some debug output ================= */ 1043 /* ================= Generate some debug output ================= */
1047 space = PAGE_SIZE; 1044 space = PAGE_SIZE;
@@ -1052,22 +1049,17 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
1052 return; 1049 return;
1053 } 1050 }
1054 1051
1055 n = snprintf(p, space, "\n"); 1052 /* Scan all the actual slots
1056 p += n;
1057 space -= n;
1058
1059 /* Scan all the actual CSROWS (which is # of DIMMS * 2)
1060 * and calculate the information for each DIMM 1053 * and calculate the information for each DIMM
1061 * Start with the highest csrow first, to display it first 1054 * Start with the highest slot first, to display it first
1062 * and work toward the 0th csrow 1055 * and work toward the 0th slot
1063 */ 1056 */
1064 max_csrows = pvt->maxdimmperch * 2; 1057 for (slot = pvt->maxdimmperch - 1; slot >= 0; slot--) {
1065 for (csrow = max_csrows - 1; csrow >= 0; csrow--) {
1066 1058
1067 /* on an odd csrow, first output a 'boundary' marker, 1059 /* on an odd slot, first output a 'boundary' marker,
1068 * then reset the message buffer */ 1060 * then reset the message buffer */
1069 if (csrow & 0x1) { 1061 if (slot & 0x1) {
1070 n = snprintf(p, space, "---------------------------" 1062 n = snprintf(p, space, "--------------------------"
1071 "--------------------------------"); 1063 "--------------------------------");
1072 p += n; 1064 p += n;
1073 space -= n; 1065 space -= n;
@@ -1075,30 +1067,39 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
1075 p = mem_buffer; 1067 p = mem_buffer;
1076 space = PAGE_SIZE; 1068 space = PAGE_SIZE;
1077 } 1069 }
1078 n = snprintf(p, space, "csrow %2d ", csrow); 1070 n = snprintf(p, space, "slot %2d ", slot);
1079 p += n; 1071 p += n;
1080 space -= n; 1072 space -= n;
1081 1073
1082 for (channel = 0; channel < pvt->maxch; channel++) { 1074 for (channel = 0; channel < pvt->maxch; channel++) {
1083 dinfo = &pvt->dimm_info[csrow][channel]; 1075 dinfo = &pvt->dimm_info[slot][channel];
1084 handle_channel(pvt, csrow, channel, dinfo); 1076 handle_channel(pvt, slot, channel, dinfo);
1085 n = snprintf(p, space, "%4d MB | ", dinfo->megabytes); 1077 if (dinfo->megabytes)
1078 n = snprintf(p, space, "%4d MB %dR| ",
1079 dinfo->megabytes, dinfo->dual_rank + 1);
1080 else
1081 n = snprintf(p, space, "%4d MB | ", 0);
1086 p += n; 1082 p += n;
1087 space -= n; 1083 space -= n;
1088 } 1084 }
1089 n = snprintf(p, space, "\n");
1090 p += n; 1085 p += n;
1091 space -= n; 1086 space -= n;
1087 debugf2("%s\n", mem_buffer);
1088 p = mem_buffer;
1089 space = PAGE_SIZE;
1092 } 1090 }
1093 1091
1094 /* Output the last bottom 'boundary' marker */ 1092 /* Output the last bottom 'boundary' marker */
1095 n = snprintf(p, space, "---------------------------" 1093 n = snprintf(p, space, "--------------------------"
1096 "--------------------------------\n"); 1094 "--------------------------------");
1097 p += n; 1095 p += n;
1098 space -= n; 1096 space -= n;
1097 debugf2("%s\n", mem_buffer);
1098 p = mem_buffer;
1099 space = PAGE_SIZE;
1099 1100
1100 /* now output the 'channel' labels */ 1101 /* now output the 'channel' labels */
1101 n = snprintf(p, space, " "); 1102 n = snprintf(p, space, " ");
1102 p += n; 1103 p += n;
1103 space -= n; 1104 space -= n;
1104 for (channel = 0; channel < pvt->maxch; channel++) { 1105 for (channel = 0; channel < pvt->maxch; channel++) {
@@ -1106,9 +1107,17 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
1106 p += n; 1107 p += n;
1107 space -= n; 1108 space -= n;
1108 } 1109 }
1109 n = snprintf(p, space, "\n"); 1110 debugf2("%s\n", mem_buffer);
1111 p = mem_buffer;
1112 space = PAGE_SIZE;
1113
1114 n = snprintf(p, space, " ");
1110 p += n; 1115 p += n;
1111 space -= n; 1116 for (branch = 0; branch < MAX_BRANCHES; branch++) {
1117 n = snprintf(p, space, " branch %d | ", branch);
1118 p += n;
1119 space -= n;
1120 }
1112 1121
1113 /* output the last message and free buffer */ 1122 /* output the last message and free buffer */
1114 debugf2("%s\n", mem_buffer); 1123 debugf2("%s\n", mem_buffer);
@@ -1241,14 +1250,13 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
1241static int i5000_init_csrows(struct mem_ctl_info *mci) 1250static int i5000_init_csrows(struct mem_ctl_info *mci)
1242{ 1251{
1243 struct i5000_pvt *pvt; 1252 struct i5000_pvt *pvt;
1244 struct csrow_info *p_csrow;
1245 struct dimm_info *dimm; 1253 struct dimm_info *dimm;
1246 int empty, channel_count; 1254 int empty, channel_count;
1247 int max_csrows; 1255 int max_csrows;
1248 int mtr, mtr1; 1256 int mtr;
1249 int csrow_megs; 1257 int csrow_megs;
1250 int channel; 1258 int channel;
1251 int csrow; 1259 int slot;
1252 1260
1253 pvt = mci->pvt_info; 1261 pvt = mci->pvt_info;
1254 1262
@@ -1258,26 +1266,25 @@ static int i5000_init_csrows(struct mem_ctl_info *mci)
1258 empty = 1; /* Assume NO memory */ 1266 empty = 1; /* Assume NO memory */
1259 1267
1260 /* 1268 /*
1261 * TODO: it would be better to not use csrow here, filling 1269 * FIXME: The memory layout used to map slot/channel into the
1262 * directly the dimm_info structs, based on branch, channel, dim number 1270 * real memory architecture is weird: branch+slot are "csrows"
1271 * and channel is channel. That required an extra array (dimm_info)
1272 * to map the dimms. A good cleanup would be to remove this array,
1273 * and do a loop here with branch, channel, slot
1263 */ 1274 */
1264 for (csrow = 0; csrow < max_csrows; csrow++) { 1275 for (slot = 0; slot < max_csrows; slot++) {
1265 p_csrow = &mci->csrows[csrow]; 1276 for (channel = 0; channel < pvt->maxch; channel++) {
1266 1277
1267 p_csrow->csrow_idx = csrow; 1278 mtr = determine_mtr(pvt, slot, channel);
1268 1279
1269 /* use branch 0 for the basis */ 1280 if (!MTR_DIMMS_PRESENT(mtr))
1270 mtr = pvt->b0_mtr[csrow >> 1]; 1281 continue;
1271 mtr1 = pvt->b1_mtr[csrow >> 1];
1272 1282
1273 /* if no DIMMS on this row, continue */ 1283 dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
1274 if (!MTR_DIMMS_PRESENT(mtr) && !MTR_DIMMS_PRESENT(mtr1)) 1284 channel / MAX_BRANCHES,
1275 continue; 1285 channel % MAX_BRANCHES, slot);
1276 1286
1277 csrow_megs = 0; 1287 csrow_megs = pvt->dimm_info[slot][channel].megabytes;
1278 for (channel = 0; channel < pvt->maxch; channel++) {
1279 dimm = p_csrow->channels[channel].dimm;
1280 csrow_megs += pvt->dimm_info[csrow][channel].megabytes;
1281 dimm->grain = 8; 1288 dimm->grain = 8;
1282 1289
1283 /* Assume DDR2 for now */ 1290 /* Assume DDR2 for now */
@@ -1290,7 +1297,7 @@ static int i5000_init_csrows(struct mem_ctl_info *mci)
1290 dimm->dtype = DEV_X4; 1297 dimm->dtype = DEV_X4;
1291 1298
1292 dimm->edac_mode = EDAC_S8ECD8ED; 1299 dimm->edac_mode = EDAC_S8ECD8ED;
1293 dimm->nr_pages = (csrow_megs << 8) / pvt->maxch; 1300 dimm->nr_pages = csrow_megs << 8;
1294 } 1301 }
1295 1302
1296 empty = 0; 1303 empty = 0;
@@ -1337,7 +1344,7 @@ static void i5000_get_dimm_and_channel_counts(struct pci_dev *pdev,
1337 * supported on this memory controller 1344 * supported on this memory controller
1338 */ 1345 */
1339 pci_read_config_byte(pdev, MAXDIMMPERCH, &value); 1346 pci_read_config_byte(pdev, MAXDIMMPERCH, &value);
1340 *num_dimms_per_channel = (int)value *2; 1347 *num_dimms_per_channel = (int)value;
1341 1348
1342 pci_read_config_byte(pdev, MAXCH, &value); 1349 pci_read_config_byte(pdev, MAXCH, &value);
1343 *num_channels = (int)value; 1350 *num_channels = (int)value;
@@ -1387,11 +1394,12 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
1387 __func__, num_channels, num_dimms_per_channel); 1394 __func__, num_channels, num_dimms_per_channel);
1388 1395
1389 /* allocate a new MC control structure */ 1396 /* allocate a new MC control structure */
1397
1390 layers[0].type = EDAC_MC_LAYER_BRANCH; 1398 layers[0].type = EDAC_MC_LAYER_BRANCH;
1391 layers[0].size = 2; 1399 layers[0].size = MAX_BRANCHES;
1392 layers[0].is_virt_csrow = true; 1400 layers[0].is_virt_csrow = false;
1393 layers[1].type = EDAC_MC_LAYER_CHANNEL; 1401 layers[1].type = EDAC_MC_LAYER_CHANNEL;
1394 layers[1].size = num_channels; 1402 layers[1].size = num_channels / MAX_BRANCHES;
1395 layers[1].is_virt_csrow = false; 1403 layers[1].is_virt_csrow = false;
1396 layers[2].type = EDAC_MC_LAYER_SLOT; 1404 layers[2].type = EDAC_MC_LAYER_SLOT;
1397 layers[2].size = num_dimms_per_channel; 1405 layers[2].size = num_dimms_per_channel;