]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: phy: dp83867: implement configurability for SGMII in-band auto-negotiation
authorVladimir Oltean <vladimir.oltean@nxp.com>
Sat, 22 Nov 2025 11:04:27 +0000 (13:04 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 27 Nov 2025 02:04:17 +0000 (18:04 -0800)
Implement the inband_caps() and config_inband() PHY driver methods, to
allow working with PCS devices that do not support or want in-band to be
used.

There is a complication due to existing logic from commit c76acfb7e19d
("net: phy: dp83867: retrigger SGMII AN when link change") which might
re-enable what dp83867_config_inband() has disabled. So we need to
modify dp83867_link_change_notify() to use phy_modify_changed() when
temporarily disabling in-band autoneg. If the return code is 0, it means
the original in-band was disabled and we need to keep it disabled.
If the return code is 1, the original was enabled and we need to
re-enable it. If negative, there was an error, which was silent before,
and remains silent now.

dp83867_config_inband() and dp83867_link_change_notify() are serialized
by the phydev->lock.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20251122110427.133035-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/phy/dp83867.c

index 36a0c1b7f59c77cb001639401b6a04078b2ef17d..5f5de01c41e1944bd952805d7f7fac3d5c6d26fa 100644 (file)
@@ -937,15 +937,15 @@ static void dp83867_link_change_notify(struct phy_device *phydev)
         * whenever there is a link change.
         */
        if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
-               int val = 0;
+               int val;
 
-               val = phy_clear_bits(phydev, DP83867_CFG2,
-                                    DP83867_SGMII_AUTONEG_EN);
-               if (val < 0)
-                       return;
+               val = phy_modify_changed(phydev, DP83867_CFG2,
+                                        DP83867_SGMII_AUTONEG_EN, 0);
 
-               phy_set_bits(phydev, DP83867_CFG2,
-                            DP83867_SGMII_AUTONEG_EN);
+               /* Keep the in-band setting made by dp83867_config_inband() */
+               if (val != 0)
+                       phy_set_bits(phydev, DP83867_CFG2,
+                                    DP83867_SGMII_AUTONEG_EN);
        }
 }
 
@@ -1116,6 +1116,25 @@ static int dp83867_led_polarity_set(struct phy_device *phydev, int index,
                          DP83867_LED_POLARITY(index), polarity);
 }
 
+static unsigned int dp83867_inband_caps(struct phy_device *phydev,
+                                       phy_interface_t interface)
+{
+       if (interface == PHY_INTERFACE_MODE_SGMII)
+               return LINK_INBAND_ENABLE | LINK_INBAND_DISABLE;
+
+       return 0;
+}
+
+static int dp83867_config_inband(struct phy_device *phydev, unsigned int modes)
+{
+       int val = 0;
+
+       if (modes == LINK_INBAND_ENABLE)
+               val = DP83867_SGMII_AUTONEG_EN;
+
+       return phy_modify(phydev, DP83867_CFG2, DP83867_SGMII_AUTONEG_EN, val);
+}
+
 static struct phy_driver dp83867_driver[] = {
        {
                .phy_id         = DP83867_PHY_ID,
@@ -1149,6 +1168,9 @@ static struct phy_driver dp83867_driver[] = {
                .led_hw_control_set = dp83867_led_hw_control_set,
                .led_hw_control_get = dp83867_led_hw_control_get,
                .led_polarity_set = dp83867_led_polarity_set,
+
+               .inband_caps    = dp83867_inband_caps,
+               .config_inband  = dp83867_config_inband,
        },
 };
 module_phy_driver(dp83867_driver);