diff options
Diffstat (limited to 'drivers/edac/amd64_edac.c')
-rw-r--r-- | drivers/edac/amd64_edac.c | 181 |
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 | */ | ||
1196 | static 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 | |||
1275 | err_reg: | ||
1276 | return -1; | ||
1277 | |||
1278 | } | ||
1279 | |||
1280 | static 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 */ | ||
1286 | static 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, ®); | ||
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 */ | ||
1298 | static 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, ®); | ||
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 | |||
1310 | static 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 | */ | ||
1323 | static 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 | } | ||