Commit c36757eb authored by Heiner Kallweit's avatar Heiner Kallweit Committed by Jakub Kicinski

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: c1164bb1 ("net: phy: check PMAPMD link status only in genphy_c45_read_link")
Tested-by: default avatarYonglong Liu <liuyonglong@huawei.com>
Signed-off-by: default avatarHeiner Kallweit <hkallweit1@gmail.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
parent 48ec7014
...@@ -219,6 +219,20 @@ int genphy_c45_read_link(struct phy_device *phydev) ...@@ -219,6 +219,20 @@ int genphy_c45_read_link(struct phy_device *phydev)
int val, devad; int val, devad;
bool link = true; bool link = true;
if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) {
val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
if (val < 0)
return val;
/* Autoneg is being started, therefore disregard current
* link status and report link as down.
*/
if (val & MDIO_AN_CTRL1_RESTART) {
phydev->link = 0;
return 0;
}
}
while (mmd_mask && link) { while (mmd_mask && link) {
devad = __ffs(mmd_mask); devad = __ffs(mmd_mask);
mmd_mask &= ~BIT(devad); mmd_mask &= ~BIT(devad);
......
...@@ -1752,7 +1752,17 @@ EXPORT_SYMBOL(genphy_aneg_done); ...@@ -1752,7 +1752,17 @@ EXPORT_SYMBOL(genphy_aneg_done);
*/ */
int genphy_update_link(struct phy_device *phydev) int genphy_update_link(struct phy_device *phydev)
{ {
int status; int status = 0, bmcr;
bmcr = phy_read(phydev, MII_BMCR);
if (bmcr < 0)
return bmcr;
/* Autoneg is being started, therefore disregard BMSR value and
* report link as down.
*/
if (bmcr & BMCR_ANRESTART)
goto done;
/* The link state is latched low so that momentary link /* The link state is latched low so that momentary link
* drops can be detected. Do not double-read the status * drops can be detected. Do not double-read the status
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment