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

net: phy: dp83867: implement configurability for SGMII in-band auto-negotiation

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>

authored by

Vladimir Oltean and committed by
Jakub Kicinski
002373a8 308b7dee

+29 -7
+29 -7
drivers/net/phy/dp83867.c
··· 937 937 * whenever there is a link change. 938 938 */ 939 939 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 940 - int val = 0; 940 + int val; 941 941 942 - val = phy_clear_bits(phydev, DP83867_CFG2, 942 + val = phy_modify_changed(phydev, DP83867_CFG2, 943 + DP83867_SGMII_AUTONEG_EN, 0); 944 + 945 + /* Keep the in-band setting made by dp83867_config_inband() */ 946 + if (val != 0) 947 + phy_set_bits(phydev, DP83867_CFG2, 943 948 DP83867_SGMII_AUTONEG_EN); 944 - if (val < 0) 945 - return; 946 - 947 - phy_set_bits(phydev, DP83867_CFG2, 948 - DP83867_SGMII_AUTONEG_EN); 949 949 } 950 950 } 951 951 ··· 1116 1116 DP83867_LED_POLARITY(index), polarity); 1117 1117 } 1118 1118 1119 + static unsigned int dp83867_inband_caps(struct phy_device *phydev, 1120 + phy_interface_t interface) 1121 + { 1122 + if (interface == PHY_INTERFACE_MODE_SGMII) 1123 + return LINK_INBAND_ENABLE | LINK_INBAND_DISABLE; 1124 + 1125 + return 0; 1126 + } 1127 + 1128 + static int dp83867_config_inband(struct phy_device *phydev, unsigned int modes) 1129 + { 1130 + int val = 0; 1131 + 1132 + if (modes == LINK_INBAND_ENABLE) 1133 + val = DP83867_SGMII_AUTONEG_EN; 1134 + 1135 + return phy_modify(phydev, DP83867_CFG2, DP83867_SGMII_AUTONEG_EN, val); 1136 + } 1137 + 1119 1138 static struct phy_driver dp83867_driver[] = { 1120 1139 { 1121 1140 .phy_id = DP83867_PHY_ID, ··· 1168 1149 .led_hw_control_set = dp83867_led_hw_control_set, 1169 1150 .led_hw_control_get = dp83867_led_hw_control_get, 1170 1151 .led_polarity_set = dp83867_led_polarity_set, 1152 + 1153 + .inband_caps = dp83867_inband_caps, 1154 + .config_inband = dp83867_config_inband, 1171 1155 }, 1172 1156 }; 1173 1157 module_phy_driver(dp83867_driver);