Commit 776829de authored by Igor Plyatov's avatar Igor Plyatov Committed by David S. Miller

net: phy: workaround for buggy cable detection by LAN8700 after cable plugging

* Due to HW bug, LAN8700 sometimes does not detect presence of energy in the
  Ethernet cable in Energy Detect Power-Down mode (e.g while EDPWRDOWN bit is
  set, the ENERGYON bit does not asserted sometimes). This is a common bug of
  LAN87xx family of PHY chips.
* The lan87xx_read_status() was improved to acquire ENERGYON bit. Its previous
  algorythm still not reliable on 100 % and sometimes skip cable plugging.
Signed-off-by: default avatarIgor Plyatov <plyatov@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a27cc68b
...@@ -91,19 +91,18 @@ static int lan911x_config_init(struct phy_device *phydev) ...@@ -91,19 +91,18 @@ static int lan911x_config_init(struct phy_device *phydev)
} }
/* /*
* The LAN8710/LAN8720 requires a minimum of 2 link pulses within 64ms of each * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable
* other in order to set the ENERGYON bit and exit EDPD mode. If a link partner * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to
* does send the pulses within this interval, the PHY will remained powered * unstable detection of plugging in Ethernet cable.
* down. * This workaround disables Energy Detect Power-Down mode and waiting for
* * response on link pulses to detect presence of plugged Ethernet cable.
* This workaround will manually toggle the PHY on/off upon calls to read_status * The Energy Detect Power-Down mode is enabled again in the end of procedure to
* in order to generate link test pulses if the link is down. If a link partner * save approximately 220 mW of power if cable is unplugged.
* is present, it will respond to the pulses, which will cause the ENERGYON bit
* to be set and will cause the EDPD mode to be exited.
*/ */
static int lan87xx_read_status(struct phy_device *phydev) static int lan87xx_read_status(struct phy_device *phydev)
{ {
int err = genphy_read_status(phydev); int err = genphy_read_status(phydev);
int i;
if (!phydev->link) { if (!phydev->link) {
/* Disable EDPD to wake up PHY */ /* Disable EDPD to wake up PHY */
...@@ -116,8 +115,16 @@ static int lan87xx_read_status(struct phy_device *phydev) ...@@ -116,8 +115,16 @@ static int lan87xx_read_status(struct phy_device *phydev)
if (rc < 0) if (rc < 0)
return rc; return rc;
/* Sleep 64 ms to allow ~5 link test pulses to be sent */ /* Wait max 640 ms to detect energy */
msleep(64); for (i = 0; i < 64; i++) {
/* Sleep to allow link test pulses to be sent */
msleep(10);
rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
if (rc < 0)
return rc;
if (rc & MII_LAN83C185_ENERGYON)
break;
};
/* Re-enable EDPD */ /* Re-enable EDPD */
rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
...@@ -191,7 +198,7 @@ static struct phy_driver smsc_phy_driver[] = { ...@@ -191,7 +198,7 @@ static struct phy_driver smsc_phy_driver[] = {
/* basic functions */ /* basic functions */
.config_aneg = genphy_config_aneg, .config_aneg = genphy_config_aneg,
.read_status = genphy_read_status, .read_status = lan87xx_read_status,
.config_init = smsc_phy_config_init, .config_init = smsc_phy_config_init,
.soft_reset = smsc_phy_reset, .soft_reset = smsc_phy_reset,
......
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