Commit 93c09704 authored by Heiner Kallweit's avatar Heiner Kallweit Committed by David S. Miller

net: phy: consider latched link-down status in polling mode

The link status value latches link-down events. To get the current
status we read the register twice in genphy_update_link(). There's
a potential risk that we miss a link-down event in polling mode.
This may cause issues if the user e.g. connects his machine to a
different network.

On the other hand reading the latched value may cause issues in
interrupt mode. Following scenario:

- After boot link goes up
- phy_start() is called triggering an aneg restart, hence link goes
  down and link-down info is latched.
- After aneg has finished link goes up and triggers an interrupt.
  Interrupt handler reads link status, means it reads the latched
  "link is down" info. But there won't be another interrupt as long
  as link stays up, therefore phylib will never recognize that link
  is up.

Deal with both scenarios by reading the register twice in interrupt
mode only.
Signed-off-by: default avatarHeiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3e3e0cdf
...@@ -142,8 +142,14 @@ int genphy_c45_read_link(struct phy_device *phydev) ...@@ -142,8 +142,14 @@ int genphy_c45_read_link(struct phy_device *phydev)
/* 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
* register if the link is down. * in polling mode to detect such short link drops.
*/ */
if (!phy_polling_mode(phydev)) {
val = phy_read_mmd(phydev, devad, MDIO_STAT1);
if (val < 0)
return val;
}
val = phy_read_mmd(phydev, devad, MDIO_STAT1); val = phy_read_mmd(phydev, devad, MDIO_STAT1);
if (val < 0) if (val < 0)
return val; return val;
......
...@@ -1729,10 +1729,15 @@ int genphy_update_link(struct phy_device *phydev) ...@@ -1729,10 +1729,15 @@ int genphy_update_link(struct phy_device *phydev)
{ {
int status; int status;
/* Do a fake read */ /* The link state is latched low so that momentary link
* drops can be detected. Do not double-read the status
* in polling mode to detect such short link drops.
*/
if (!phy_polling_mode(phydev)) {
status = phy_read(phydev, MII_BMSR); status = phy_read(phydev, MII_BMSR);
if (status < 0) if (status < 0)
return status; return status;
}
/* Read link and autonegotiation status */ /* Read link and autonegotiation status */
status = phy_read(phydev, MII_BMSR); status = phy_read(phydev, MII_BMSR);
......
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