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

net: phy: consider AN_RESTART status when reading link status

After configuring and restarting aneg we immediately try to read the
link status. On some systems the PHY may not yet have cleared the
"aneg complete" and "link up" bits, resulting in a false link-up
signal. See [0] for a report.
Clause 22 and 45 both require the PHY to keep the AN_RESTART
bit set until the PHY actually starts auto-negotiation.
Let's consider this in the generic functions for reading link status.
The commit marked as fixed is the first one where the patch applies
cleanly.

[0] https://marc.info/?t=156518400300003&r=1&w=2

Fixes: c1164bb1a631 ("net: phy: check PMAPMD link status only in genphy_c45_read_link")
Tested-by: Yonglong Liu <liuyonglong@huawei.com>
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>

authored by

Heiner Kallweit and committed by
Jakub Kicinski
c36757eb 48ec7014

+25 -1
+14
drivers/net/phy/phy-c45.c
··· 219 219 int val, devad; 220 220 bool link = true; 221 221 222 + if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) { 223 + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); 224 + if (val < 0) 225 + return val; 226 + 227 + /* Autoneg is being started, therefore disregard current 228 + * link status and report link as down. 229 + */ 230 + if (val & MDIO_AN_CTRL1_RESTART) { 231 + phydev->link = 0; 232 + return 0; 233 + } 234 + } 235 + 222 236 while (mmd_mask && link) { 223 237 devad = __ffs(mmd_mask); 224 238 mmd_mask &= ~BIT(devad);
+11 -1
drivers/net/phy/phy_device.c
··· 1752 1752 */ 1753 1753 int genphy_update_link(struct phy_device *phydev) 1754 1754 { 1755 - int status; 1755 + int status = 0, bmcr; 1756 + 1757 + bmcr = phy_read(phydev, MII_BMCR); 1758 + if (bmcr < 0) 1759 + return bmcr; 1760 + 1761 + /* Autoneg is being started, therefore disregard BMSR value and 1762 + * report link as down. 1763 + */ 1764 + if (bmcr & BMCR_ANRESTART) 1765 + goto done; 1756 1766 1757 1767 /* The link state is latched low so that momentary link 1758 1768 * drops can be detected. Do not double-read the status