summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiner Kallweit <hkallweit1@gmail.com>2019-08-12 21:20:02 +0200
committerSasha Levin <sashal@kernel.org>2019-08-25 10:10:38 -0400
commit9a31192e1ca12e5e7c80c3600ede8c660728c8f4 (patch)
tree6ff57453fd608dc8d476a6d68f4d355949cf754a
parentbc110443a73f275de83d691bccbba9ecd25ca9be (diff)
downloadlinux-stable-9a31192e1ca12e5e7c80c3600ede8c660728c8f4.tar.gz
linux-stable-9a31192e1ca12e5e7c80c3600ede8c660728c8f4.tar.bz2
linux-stable-9a31192e1ca12e5e7c80c3600ede8c660728c8f4.zip
net: phy: consider AN_RESTART status when reading link status
[ Upstream commit c36757eb9dee13681227ad3676d37f14b3a2b2af ] 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/net/phy/phy-c45.c14
-rw-r--r--drivers/net/phy/phy_device.c12
2 files changed, 25 insertions, 1 deletions
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index b9d4145781ca..58bb25e4af10 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -219,6 +219,20 @@ int genphy_c45_read_link(struct phy_device *phydev)
int val, devad;
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) {
devad = __ffs(mmd_mask);
mmd_mask &= ~BIT(devad);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ffa402732aea..3af0af495cf1 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1708,7 +1708,17 @@ EXPORT_SYMBOL(genphy_aneg_done);
*/
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
* drops can be detected. Do not double-read the status