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.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index b4ef2c70500e..744a49ac9f5c 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -1367,3 +1367,199 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
1367 pvt->dram_limit[dram] = 1367 pvt->dram_limit[dram] =
1368 ((((u64) high_limit << 32) + (u64) low_limit) << 8) | (0xFF); 1368 ((((u64) high_limit << 32) + (u64) low_limit) << 8) | (0xFF);
1369} 1369}
1370
1371static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)
1372{
1373 int err = 0;
1374
1375 err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCTL_SEL_LOW,
1376 &pvt->dram_ctl_select_low);
1377 if (err) {
1378 debugf0("Reading F10_DCTL_SEL_LOW failed\n");
1379 } else {
1380 debugf0("DRAM_DCTL_SEL_LOW=0x%x DctSelBaseAddr=0x%x\n",
1381 pvt->dram_ctl_select_low, dct_sel_baseaddr(pvt));
1382
1383 debugf0(" DRAM DCTs are=%s DRAM Is=%s DRAM-Ctl-"
1384 "sel-hi-range=%s\n",
1385 (dct_ganging_enabled(pvt) ? "GANGED" : "NOT GANGED"),
1386 (dct_dram_enabled(pvt) ? "Enabled" : "Disabled"),
1387 (dct_high_range_enabled(pvt) ? "Enabled" : "Disabled"));
1388
1389 debugf0(" DctDatIntLv=%s MemCleared=%s DctSelIntLvAddr=0x%x\n",
1390 (dct_data_intlv_enabled(pvt) ? "Enabled" : "Disabled"),
1391 (dct_memory_cleared(pvt) ? "True " : "False "),
1392 dct_sel_interleave_addr(pvt));
1393 }
1394
1395 err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCTL_SEL_HIGH,
1396 &pvt->dram_ctl_select_high);
1397 if (err)
1398 debugf0("Reading F10_DCTL_SEL_HIGH failed\n");
1399}
1400
1401static u32 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
1402 int hi_range_sel, u32 intlv_en)
1403{
1404 u32 cs, temp, dct_sel_high = (pvt->dram_ctl_select_low >> 1) & 1;
1405
1406 if (dct_ganging_enabled(pvt))
1407 cs = 0;
1408 else if (hi_range_sel)
1409 cs = dct_sel_high;
1410 else if (dct_interleave_enabled(pvt)) {
1411 if (dct_sel_interleave_addr(pvt) == 0)
1412 cs = sys_addr >> 6 & 1;
1413 else if ((dct_sel_interleave_addr(pvt) >> 1) & 1) {
1414 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2;
1415
1416 if (dct_sel_interleave_addr(pvt) & 1)
1417 cs = (sys_addr >> 9 & 1) ^ temp;
1418 else
1419 cs = (sys_addr >> 6 & 1) ^ temp;
1420 } else if (intlv_en & 4)
1421 cs = sys_addr >> 15 & 1;
1422 else if (intlv_en & 2)
1423 cs = sys_addr >> 14 & 1;
1424 else if (intlv_en & 1)
1425 cs = sys_addr >> 13 & 1;
1426 else
1427 cs = sys_addr >> 12 & 1;
1428 } else if (dct_high_range_enabled(pvt) && !dct_ganging_enabled(pvt))
1429 cs = ~dct_sel_high & 1;
1430 else
1431 cs = 0;
1432
1433 return cs;
1434}
1435
1436static inline u32 f10_map_intlv_en_to_shift(u32 intlv_en)
1437{
1438 if (intlv_en == 1)
1439 return 1;
1440 else if (intlv_en == 3)
1441 return 2;
1442 else if (intlv_en == 7)
1443 return 3;
1444
1445 return 0;
1446}
1447
1448static inline u64 f10_determine_base_addr_offset(u64 sys_addr, int hi_range_sel,
1449 u32 dct_sel_base_addr,
1450 u64 dct_sel_base_off,
1451 u32 hole_en, u32 hole_off,
1452 u64 dram_base)
1453{
1454 u64 chan_off;
1455
1456 if (hi_range_sel) {
1457 if (!(dct_sel_base_addr & 0xFFFFF800) &&
1458 (hole_en & 1) && (sys_addr >= 0x100000000ULL))
1459 chan_off = hole_off << 16;
1460 else
1461 chan_off = dct_sel_base_off;
1462 } else {
1463 if ((hole_en & 1) && (sys_addr >= 0x100000000ULL))
1464 chan_off = hole_off << 16;
1465 else
1466 chan_off = dram_base & 0xFFFFF8000000ULL;
1467 }
1468
1469 return (sys_addr & 0x0000FFFFFFFFFFC0ULL) -
1470 (chan_off & 0x0000FFFFFF800000ULL);
1471}
1472
1473/* Hack for the time being - Can we get this from BIOS?? */
1474#define CH0SPARE_RANK 0
1475#define CH1SPARE_RANK 1
1476
1477/*
1478 * checks if the csrow passed in is marked as SPARED, if so returns the new
1479 * spare row
1480 */
1481static inline int f10_process_possible_spare(int csrow,
1482 u32 cs, struct amd64_pvt *pvt)
1483{
1484 u32 swap_done;
1485 u32 bad_dram_cs;
1486
1487 /* Depending on channel, isolate respective SPARING info */
1488 if (cs) {
1489 swap_done = F10_ONLINE_SPARE_SWAPDONE1(pvt->online_spare);
1490 bad_dram_cs = F10_ONLINE_SPARE_BADDRAM_CS1(pvt->online_spare);
1491 if (swap_done && (csrow == bad_dram_cs))
1492 csrow = CH1SPARE_RANK;
1493 } else {
1494 swap_done = F10_ONLINE_SPARE_SWAPDONE0(pvt->online_spare);
1495 bad_dram_cs = F10_ONLINE_SPARE_BADDRAM_CS0(pvt->online_spare);
1496 if (swap_done && (csrow == bad_dram_cs))
1497 csrow = CH0SPARE_RANK;
1498 }
1499 return csrow;
1500}
1501
1502/*
1503 * Iterate over the DRAM DCT "base" and "mask" registers looking for a
1504 * SystemAddr match on the specified 'ChannelSelect' and 'NodeID'
1505 *
1506 * Return:
1507 * -EINVAL: NOT FOUND
1508 * 0..csrow = Chip-Select Row
1509 */
1510static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs)
1511{
1512 struct mem_ctl_info *mci;
1513 struct amd64_pvt *pvt;
1514 u32 cs_base, cs_mask;
1515 int cs_found = -EINVAL;
1516 int csrow;
1517
1518 mci = mci_lookup[nid];
1519 if (!mci)
1520 return cs_found;
1521
1522 pvt = mci->pvt_info;
1523
1524 debugf1("InputAddr=0x%x channelselect=%d\n", in_addr, cs);
1525
1526 for (csrow = 0; csrow < CHIPSELECT_COUNT; csrow++) {
1527
1528 cs_base = amd64_get_dct_base(pvt, cs, csrow);
1529 if (!(cs_base & K8_DCSB_CS_ENABLE))
1530 continue;
1531
1532 /*
1533 * We have an ENABLED CSROW, Isolate just the MASK bits of the
1534 * target: [28:19] and [13:5], which map to [36:27] and [21:13]
1535 * of the actual address.
1536 */
1537 cs_base &= REV_F_F1Xh_DCSB_BASE_BITS;
1538
1539 /*
1540 * Get the DCT Mask, and ENABLE the reserved bits: [18:16] and
1541 * [4:0] to become ON. Then mask off bits [28:0] ([36:8])
1542 */
1543 cs_mask = amd64_get_dct_mask(pvt, cs, csrow);
1544
1545 debugf1(" CSROW=%d CSBase=0x%x RAW CSMask=0x%x\n",
1546 csrow, cs_base, cs_mask);
1547
1548 cs_mask = (cs_mask | 0x0007C01F) & 0x1FFFFFFF;
1549
1550 debugf1(" Final CSMask=0x%x\n", cs_mask);
1551 debugf1(" (InputAddr & ~CSMask)=0x%x "
1552 "(CSBase & ~CSMask)=0x%x\n",
1553 (in_addr & ~cs_mask), (cs_base & ~cs_mask));
1554
1555 if ((in_addr & ~cs_mask) == (cs_base & ~cs_mask)) {
1556 cs_found = f10_process_possible_spare(csrow, cs, pvt);
1557
1558 debugf1(" MATCH csrow=%d\n", cs_found);
1559 break;
1560 }
1561 }
1562 return cs_found;
1563}
1564
1565