aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/amd64_edac.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/edac/amd64_edac.c')
-rw-r--r--drivers/edac/amd64_edac.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 24c031f79756..b4ef2c70500e 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -1185,4 +1185,185 @@ static int k8_dbam_map_to_pages(struct amd64_pvt *pvt, int dram_map)
1185 return nr_pages; 1185 return nr_pages;
1186} 1186}
1187 1187
1188/*
1189 * Get the number of DCT channels in use.
1190 *
1191 * Return:
1192 * number of Memory Channels in operation
1193 * Pass back:
1194 * contents of the DCL0_LOW register
1195 */
1196static int f10_early_channel_count(struct amd64_pvt *pvt)
1197{
1198 int err = 0, channels = 0;
1199 u32 dbam;
1200
1201 err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0);
1202 if (err)
1203 goto err_reg;
1204
1205 err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1);
1206 if (err)
1207 goto err_reg;
1208
1209 /* If we are in 128 bit mode, then we are using 2 channels */
1210 if (pvt->dclr0 & F10_WIDTH_128) {
1211 debugf0("Data WIDTH is 128 bits - 2 channels\n");
1212 channels = 2;
1213 return channels;
1214 }
1215
1216 /*
1217 * Need to check if in UN-ganged mode: In such, there are 2 channels,
1218 * but they are NOT in 128 bit mode and thus the above 'dcl0' status bit
1219 * will be OFF.
1220 *
1221 * Need to check DCT0[0] and DCT1[0] to see if only one of them has
1222 * their CSEnable bit on. If so, then SINGLE DIMM case.
1223 */
1224 debugf0("Data WIDTH is NOT 128 bits - need more decoding\n");
1188 1225
1226 /*
1227 * Check DRAM Bank Address Mapping values for each DIMM to see if there
1228 * is more than just one DIMM present in unganged mode. Need to check
1229 * both controllers since DIMMs can be placed in either one.
1230 */
1231 channels = 0;
1232 err = pci_read_config_dword(pvt->dram_f2_ctl, DBAM0, &dbam);
1233 if (err)
1234 goto err_reg;
1235
1236 if (DBAM_DIMM(0, dbam) > 0)
1237 channels++;
1238 if (DBAM_DIMM(1, dbam) > 0)
1239 channels++;
1240 if (DBAM_DIMM(2, dbam) > 0)
1241 channels++;
1242 if (DBAM_DIMM(3, dbam) > 0)
1243 channels++;
1244
1245 /* If more than 2 DIMMs are present, then we have 2 channels */
1246 if (channels > 2)
1247 channels = 2;
1248 else if (channels == 0) {
1249 /* No DIMMs on DCT0, so look at DCT1 */
1250 err = pci_read_config_dword(pvt->dram_f2_ctl, DBAM1, &dbam);
1251 if (err)
1252 goto err_reg;
1253
1254 if (DBAM_DIMM(0, dbam) > 0)
1255 channels++;
1256 if (DBAM_DIMM(1, dbam) > 0)
1257 channels++;
1258 if (DBAM_DIMM(2, dbam) > 0)
1259 channels++;
1260 if (DBAM_DIMM(3, dbam) > 0)
1261 channels++;
1262
1263 if (channels > 2)
1264 channels = 2;
1265 }
1266
1267 /* If we found ALL 0 values, then assume just ONE DIMM-ONE Channel */
1268 if (channels == 0)
1269 channels = 1;
1270
1271 debugf0("DIMM count= %d\n", channels);
1272
1273 return channels;
1274
1275err_reg:
1276 return -1;
1277
1278}
1279
1280static int f10_dbam_map_to_pages(struct amd64_pvt *pvt, int dram_map)
1281{
1282 return 1 << (revf_quad_ddr2_shift[dram_map] - PAGE_SHIFT);
1283}
1284
1285/* Enable extended configuration access via 0xCF8 feature */
1286static void amd64_setup(struct amd64_pvt *pvt)
1287{
1288 u32 reg;
1289
1290 pci_read_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, &reg);
1291
1292 pvt->flags.cf8_extcfg = !!(reg & F10_NB_CFG_LOW_ENABLE_EXT_CFG);
1293 reg |= F10_NB_CFG_LOW_ENABLE_EXT_CFG;
1294 pci_write_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, reg);
1295}
1296
1297/* Restore the extended configuration access via 0xCF8 feature */
1298static void amd64_teardown(struct amd64_pvt *pvt)
1299{
1300 u32 reg;
1301
1302 pci_read_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, &reg);
1303
1304 reg &= ~F10_NB_CFG_LOW_ENABLE_EXT_CFG;
1305 if (pvt->flags.cf8_extcfg)
1306 reg |= F10_NB_CFG_LOW_ENABLE_EXT_CFG;
1307 pci_write_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, reg);
1308}
1309
1310static u64 f10_get_error_address(struct mem_ctl_info *mci,
1311 struct amd64_error_info_regs *info)
1312{
1313 return (((u64) (info->nbeah & 0xffff)) << 32) +
1314 (info->nbeal & ~0x01);
1315}
1316
1317/*
1318 * Read the Base and Limit registers for F10 based Memory controllers. Extract
1319 * fields from the 'raw' reg into separate data fields.
1320 *
1321 * Isolates: BASE, LIMIT, IntlvEn, IntlvSel, RW_EN.
1322 */
1323static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
1324{
1325 u32 high_offset, low_offset, high_base, low_base, high_limit, low_limit;
1326
1327 low_offset = K8_DRAM_BASE_LOW + (dram << 3);
1328 high_offset = F10_DRAM_BASE_HIGH + (dram << 3);
1329
1330 /* read the 'raw' DRAM BASE Address register */
1331 pci_read_config_dword(pvt->addr_f1_ctl, low_offset, &low_base);
1332
1333 /* Read from the ECS data register */
1334 pci_read_config_dword(pvt->addr_f1_ctl, high_offset, &high_base);
1335
1336 /* Extract parts into separate data entries */
1337 pvt->dram_rw_en[dram] = (low_base & 0x3);
1338
1339 if (pvt->dram_rw_en[dram] == 0)
1340 return;
1341
1342 pvt->dram_IntlvEn[dram] = (low_base >> 8) & 0x7;
1343
1344 pvt->dram_base[dram] = (((((u64) high_base & 0x000000FF) << 32) |
1345 ((u64) low_base & 0xFFFF0000))) << 8;
1346
1347 low_offset = K8_DRAM_LIMIT_LOW + (dram << 3);
1348 high_offset = F10_DRAM_LIMIT_HIGH + (dram << 3);
1349
1350 /* read the 'raw' LIMIT registers */
1351 pci_read_config_dword(pvt->addr_f1_ctl, low_offset, &low_limit);
1352
1353 /* Read from the ECS data register for the HIGH portion */
1354 pci_read_config_dword(pvt->addr_f1_ctl, high_offset, &high_limit);
1355
1356 debugf0(" HW Regs: BASE=0x%08x-%08x LIMIT= 0x%08x-%08x\n",
1357 high_base, low_base, high_limit, low_limit);
1358
1359 pvt->dram_DstNode[dram] = (low_limit & 0x7);
1360 pvt->dram_IntlvSel[dram] = (low_limit >> 8) & 0x7;
1361
1362 /*
1363 * Extract address values and form a LIMIT address. Limit is the HIGHEST
1364 * memory location of the region, so low 24 bits need to be all ones.
1365 */
1366 low_limit |= 0x0000FFFF;
1367 pvt->dram_limit[dram] =
1368 ((((u64) high_limit << 32) + (u64) low_limit) << 8) | (0xFF);
1369}