Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: phy: realtek: Add RTL8224 cable testing support

The RTL8224 can detect open pairs and short types (in same pair or some
other pair). The distance to this problem can be estimated. This is done
for each of the 4 pairs separately.

It is not meant to be run while there is an active link partner because
this interferes with the active test pulses.

Output with open 50 m cable:

Pair A code Open Circuit, source: TDR
Pair A, fault length: 51.79m, source: TDR
Pair B code Open Circuit, source: TDR
Pair B, fault length: 51.28m, source: TDR
Pair C code Open Circuit, source: TDR
Pair C, fault length: 50.46m, source: TDR
Pair D code Open Circuit, source: TDR
Pair D, fault length: 51.12m, source: TDR

Terminated cable:

Pair A code OK, source: TDR
Pair B code OK, source: TDR
Pair C code OK, source: TDR
Pair D code OK, source: TDR

Shorted cable (both short types are at roughly the same distance)

Pair A code Short to another pair, source: TDR
Pair A, fault length: 2.35m, source: TDR
Pair B code Short to another pair, source: TDR
Pair B, fault length: 2.15m, source: TDR
Pair C code OK, source: TDR
Pair D code Short within Pair, source: TDR
Pair D, fault length: 1.94m, source: TDR

Signed-off-by: Issam Hamdi <ih@simonwunderlich.de>
Co-developed-by: Sven Eckelmann <se@simonwunderlich.de>
Signed-off-by: Sven Eckelmann <se@simonwunderlich.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20251024-rtl8224-cable-test-v1-1-e3cda89ac98f@simonwunderlich.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Issam Hamdi and committed by
Jakub Kicinski
61958b33 e9ce7f49

+187
+187
drivers/net/phy/realtek/realtek_main.c
··· 8 8 * Copyright (c) 2004 Freescale Semiconductor, Inc. 9 9 */ 10 10 #include <linux/bitops.h> 11 + #include <linux/ethtool_netlink.h> 11 12 #include <linux/of.h> 12 13 #include <linux/phy.h> 13 14 #include <linux/pm_wakeirq.h> ··· 127 126 * is set, they cannot be accessed by C45-over-C22. 128 127 */ 129 128 #define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg)) 129 + 130 + #define RTL8224_MII_RTCT 0x11 131 + #define RTL8224_MII_RTCT_ENABLE BIT(0) 132 + #define RTL8224_MII_RTCT_PAIR_A BIT(4) 133 + #define RTL8224_MII_RTCT_PAIR_B BIT(5) 134 + #define RTL8224_MII_RTCT_PAIR_C BIT(6) 135 + #define RTL8224_MII_RTCT_PAIR_D BIT(7) 136 + #define RTL8224_MII_RTCT_DONE BIT(15) 137 + 138 + #define RTL8224_MII_SRAM_ADDR 0x1b 139 + #define RTL8224_MII_SRAM_DATA 0x1c 140 + 141 + #define RTL8224_SRAM_RTCT_FAULT(pair) (0x8026 + (pair) * 4) 142 + #define RTL8224_SRAM_RTCT_FAULT_BUSY BIT(0) 143 + #define RTL8224_SRAM_RTCT_FAULT_OPEN BIT(3) 144 + #define RTL8224_SRAM_RTCT_FAULT_SAME_SHORT BIT(4) 145 + #define RTL8224_SRAM_RTCT_FAULT_OK BIT(5) 146 + #define RTL8224_SRAM_RTCT_FAULT_DONE BIT(6) 147 + #define RTL8224_SRAM_RTCT_FAULT_CROSS_SHORT BIT(7) 148 + 149 + #define RTL8224_SRAM_RTCT_LEN(pair) (0x8028 + (pair) * 4) 130 150 131 151 #define RTL8366RB_POWER_SAVE 0x15 132 152 #define RTL8366RB_POWER_SAVE_ON BIT(12) ··· 1475 1453 return 0; 1476 1454 } 1477 1455 1456 + static int rtl8224_cable_test_start(struct phy_device *phydev) 1457 + { 1458 + u32 val; 1459 + int ret; 1460 + 1461 + /* disable auto-negotiation and force 1000/Full */ 1462 + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, 1463 + RTL822X_VND2_C22_REG(MII_BMCR), 1464 + BMCR_ANENABLE | BMCR_SPEED100 | BMCR_SPEED10, 1465 + BMCR_SPEED1000 | BMCR_FULLDPLX); 1466 + if (ret) 1467 + return ret; 1468 + 1469 + mdelay(500); 1470 + 1471 + /* trigger cable test */ 1472 + val = RTL8224_MII_RTCT_ENABLE; 1473 + val |= RTL8224_MII_RTCT_PAIR_A; 1474 + val |= RTL8224_MII_RTCT_PAIR_B; 1475 + val |= RTL8224_MII_RTCT_PAIR_C; 1476 + val |= RTL8224_MII_RTCT_PAIR_D; 1477 + 1478 + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, 1479 + RTL822X_VND2_C22_REG(RTL8224_MII_RTCT), 1480 + RTL8224_MII_RTCT_DONE, val); 1481 + } 1482 + 1483 + static int rtl8224_sram_read(struct phy_device *phydev, u32 reg) 1484 + { 1485 + int ret; 1486 + 1487 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 1488 + RTL822X_VND2_C22_REG(RTL8224_MII_SRAM_ADDR), 1489 + reg); 1490 + if (ret) 1491 + return ret; 1492 + 1493 + return phy_read_mmd(phydev, MDIO_MMD_VEND2, 1494 + RTL822X_VND2_C22_REG(RTL8224_MII_SRAM_DATA)); 1495 + } 1496 + 1497 + static int rtl8224_pair_len_get(struct phy_device *phydev, u32 pair) 1498 + { 1499 + int cable_len; 1500 + u32 reg_len; 1501 + int ret; 1502 + u32 cm; 1503 + 1504 + reg_len = RTL8224_SRAM_RTCT_LEN(pair); 1505 + 1506 + ret = rtl8224_sram_read(phydev, reg_len); 1507 + if (ret < 0) 1508 + return ret; 1509 + 1510 + cable_len = ret & 0xff00; 1511 + 1512 + ret = rtl8224_sram_read(phydev, reg_len + 1); 1513 + if (ret < 0) 1514 + return ret; 1515 + 1516 + cable_len |= (ret & 0xff00) >> 8; 1517 + 1518 + cable_len -= 620; 1519 + cable_len = max(cable_len, 0); 1520 + 1521 + cm = cable_len * 100 / 78; 1522 + 1523 + return cm; 1524 + } 1525 + 1526 + static int rtl8224_cable_test_result_trans(u32 result) 1527 + { 1528 + if (!(result & RTL8224_SRAM_RTCT_FAULT_DONE)) 1529 + return -EBUSY; 1530 + 1531 + if (result & RTL8224_SRAM_RTCT_FAULT_OK) 1532 + return ETHTOOL_A_CABLE_RESULT_CODE_OK; 1533 + 1534 + if (result & RTL8224_SRAM_RTCT_FAULT_OPEN) 1535 + return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; 1536 + 1537 + if (result & RTL8224_SRAM_RTCT_FAULT_SAME_SHORT) 1538 + return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; 1539 + 1540 + if (result & RTL8224_SRAM_RTCT_FAULT_BUSY) 1541 + return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 1542 + 1543 + if (result & RTL8224_SRAM_RTCT_FAULT_CROSS_SHORT) 1544 + return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; 1545 + 1546 + return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 1547 + } 1548 + 1549 + static int rtl8224_cable_test_report_pair(struct phy_device *phydev, unsigned int pair) 1550 + { 1551 + int fault_rslt; 1552 + int ret; 1553 + 1554 + ret = rtl8224_sram_read(phydev, RTL8224_SRAM_RTCT_FAULT(pair)); 1555 + if (ret < 0) 1556 + return ret; 1557 + 1558 + fault_rslt = rtl8224_cable_test_result_trans(ret); 1559 + if (fault_rslt < 0) 1560 + return 0; 1561 + 1562 + ret = ethnl_cable_test_result(phydev, pair, fault_rslt); 1563 + if (ret < 0) 1564 + return ret; 1565 + 1566 + switch (fault_rslt) { 1567 + case ETHTOOL_A_CABLE_RESULT_CODE_OPEN: 1568 + case ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT: 1569 + case ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT: 1570 + ret = rtl8224_pair_len_get(phydev, pair); 1571 + if (ret < 0) 1572 + return ret; 1573 + 1574 + return ethnl_cable_test_fault_length(phydev, pair, ret); 1575 + default: 1576 + return 0; 1577 + } 1578 + } 1579 + 1580 + static int rtl8224_cable_test_report(struct phy_device *phydev, bool *finished) 1581 + { 1582 + unsigned int pair; 1583 + int ret; 1584 + 1585 + for (pair = ETHTOOL_A_CABLE_PAIR_A; pair <= ETHTOOL_A_CABLE_PAIR_D; pair++) { 1586 + ret = rtl8224_cable_test_report_pair(phydev, pair); 1587 + if (ret == -EBUSY) { 1588 + *finished = false; 1589 + return 0; 1590 + } 1591 + 1592 + if (ret < 0) 1593 + return ret; 1594 + } 1595 + 1596 + return 0; 1597 + } 1598 + 1599 + static int rtl8224_cable_test_get_status(struct phy_device *phydev, bool *finished) 1600 + { 1601 + int ret; 1602 + 1603 + *finished = false; 1604 + 1605 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, 1606 + RTL822X_VND2_C22_REG(RTL8224_MII_RTCT)); 1607 + if (ret < 0) 1608 + return ret; 1609 + 1610 + if (!(ret & RTL8224_MII_RTCT_DONE)) 1611 + return 0; 1612 + 1613 + *finished = true; 1614 + 1615 + return rtl8224_cable_test_report(phydev, finished); 1616 + } 1617 + 1478 1618 static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) 1479 1619 { 1480 1620 int val; ··· 2114 1930 }, { 2115 1931 PHY_ID_MATCH_EXACT(0x001ccad0), 2116 1932 .name = "RTL8224 2.5Gbps PHY", 1933 + .flags = PHY_POLL_CABLE_TEST, 2117 1934 .get_features = rtl822x_c45_get_features, 2118 1935 .config_aneg = rtl822x_c45_config_aneg, 2119 1936 .read_status = rtl822x_c45_read_status, 2120 1937 .suspend = genphy_c45_pma_suspend, 2121 1938 .resume = rtlgen_c45_resume, 1939 + .cable_test_start = rtl8224_cable_test_start, 1940 + .cable_test_get_status = rtl8224_cable_test_get_status, 2122 1941 }, { 2123 1942 PHY_ID_MATCH_EXACT(0x001cc961), 2124 1943 .name = "RTL8366RB Gigabit Ethernet",