]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: phy: micrel: add cable test support for KSZ9477-class PHYs
authorOleksij Rempel <o.rempel@pengutronix.de>
Tue, 10 Jun 2025 09:13:54 +0000 (11:13 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 12 Jun 2025 00:37:48 +0000 (17:37 -0700)
Enable cable test support for KSZ9477-class PHYs by reusing the
existing KSZ9131 implementation.

This also adds support for 100Mbit-only PHYs like KSZ8563, which are
identified as KSZ9477. For these PHYs, only two wire pairs (A and B)
are active, so the cable test logic limits the pair_mask accordingly.

Support for KSZ8563 is untested but added based on its register
compatibility and PHY ID match.

Tested on KSZ9893 (Gigabit): open and short conditions were correctly
detected on all four pairs. Fault length reporting is functional and
varies by pair. For example:
- 2m cable: open faults reported ~1.2m (pairs B–D), 0.0m (pair A)
- No cable: all pairs report 0.0m fault length

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20250610091354.4060454-4-o.rempel@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/phy/micrel.c

index 68d86383e6c7a0820c1ad958b52b66c087413053..d0429dc8f56134be842bfd0dfb1092f8390b52dd 100644 (file)
@@ -1723,7 +1723,8 @@ static int ksz9x31_cable_test_fault_length(struct phy_device *phydev, u16 stat)
         *
         * distance to fault = (VCT_DATA - 22) * 4 / cable propagation velocity
         */
-       if (phydev_id_compare(phydev, PHY_ID_KSZ9131))
+       if (phydev_id_compare(phydev, PHY_ID_KSZ9131) ||
+           phydev_id_compare(phydev, PHY_ID_KSZ9477))
                dt = clamp(dt - 22, 0, 255);
 
        return (dt * 400) / 10;
@@ -1797,12 +1798,20 @@ static int ksz9x31_cable_test_get_status(struct phy_device *phydev,
                                         bool *finished)
 {
        struct kszphy_priv *priv = phydev->priv;
-       unsigned long pair_mask = 0xf;
+       unsigned long pair_mask;
        int retries = 20;
        int pair, ret, rv;
 
        *finished = false;
 
+       if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+                             phydev->supported) ||
+           linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+                             phydev->supported))
+               pair_mask = 0xf; /* All pairs */
+       else
+               pair_mask = 0x3; /* Pairs A and B only */
+
        /* Try harder if link partner is active */
        while (pair_mask && retries--) {
                for_each_set_bit(pair, &pair_mask, 4) {
@@ -5790,6 +5799,8 @@ static struct phy_driver ksphy_driver[] = {
        .resume         = ksz9477_resume,
        .get_phy_stats  = kszphy_get_phy_stats,
        .update_stats   = kszphy_update_stats,
+       .cable_test_start       = ksz9x31_cable_test_start,
+       .cable_test_get_status  = ksz9x31_cable_test_get_status,
 } };
 
 module_phy_driver(ksphy_driver);