Commit 51e2a384 authored by Trent Piepho's avatar Trent Piepho Committed by David S. Miller

PHY: Avoid unnecessary aneg restarts

The PHY's aneg is configured and restarted whenever the link is brought up,
e.g. when DHCP is started after the kernel has booted.  This can take the
link down for several seconds while auto-negotiation is redone.

If the advertised features haven't changed, then it shouldn't be necessary
to bring down the link and start auto-negotiation over again.

genphy_config_advert() is enhanced to return 0 when the advertised features
haven't been changed and >0 when they have been.

genphy_config_aneg() then uses this information to not call
genphy_restart_aneg() if there has been no change.
Signed-off-by: default avatarTrent Piepho <tpiepho@freescale.com>
Acked-by: default avatarAndy Fleming <afleming@freescale.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7bf6bf48
...@@ -419,13 +419,14 @@ EXPORT_SYMBOL(phy_detach); ...@@ -419,13 +419,14 @@ EXPORT_SYMBOL(phy_detach);
* *
* Description: Writes MII_ADVERTISE with the appropriate values, * Description: Writes MII_ADVERTISE with the appropriate values,
* after sanitizing the values to make sure we only advertise * after sanitizing the values to make sure we only advertise
* what is supported. * what is supported. Returns < 0 on error, 0 if the PHY's advertisement
* hasn't changed, and > 0 if it has changed.
*/ */
int genphy_config_advert(struct phy_device *phydev) int genphy_config_advert(struct phy_device *phydev)
{ {
u32 advertise; u32 advertise;
int adv; int oldadv, adv;
int err; int err, changed = 0;
/* Only allow advertising what /* Only allow advertising what
* this PHY supports */ * this PHY supports */
...@@ -433,7 +434,7 @@ int genphy_config_advert(struct phy_device *phydev) ...@@ -433,7 +434,7 @@ int genphy_config_advert(struct phy_device *phydev)
advertise = phydev->advertising; advertise = phydev->advertising;
/* Setup standard advertisement */ /* Setup standard advertisement */
adv = phy_read(phydev, MII_ADVERTISE); oldadv = adv = phy_read(phydev, MII_ADVERTISE);
if (adv < 0) if (adv < 0)
return adv; return adv;
...@@ -453,15 +454,18 @@ int genphy_config_advert(struct phy_device *phydev) ...@@ -453,15 +454,18 @@ int genphy_config_advert(struct phy_device *phydev)
if (advertise & ADVERTISED_Asym_Pause) if (advertise & ADVERTISED_Asym_Pause)
adv |= ADVERTISE_PAUSE_ASYM; adv |= ADVERTISE_PAUSE_ASYM;
if (adv != oldadv) {
err = phy_write(phydev, MII_ADVERTISE, adv); err = phy_write(phydev, MII_ADVERTISE, adv);
if (err < 0) if (err < 0)
return err; return err;
changed = 1;
}
/* Configure gigabit if it's supported */ /* Configure gigabit if it's supported */
if (phydev->supported & (SUPPORTED_1000baseT_Half | if (phydev->supported & (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full)) { SUPPORTED_1000baseT_Full)) {
adv = phy_read(phydev, MII_CTRL1000); oldadv = adv = phy_read(phydev, MII_CTRL1000);
if (adv < 0) if (adv < 0)
return adv; return adv;
...@@ -471,13 +475,17 @@ int genphy_config_advert(struct phy_device *phydev) ...@@ -471,13 +475,17 @@ int genphy_config_advert(struct phy_device *phydev)
adv |= ADVERTISE_1000HALF; adv |= ADVERTISE_1000HALF;
if (advertise & SUPPORTED_1000baseT_Full) if (advertise & SUPPORTED_1000baseT_Full)
adv |= ADVERTISE_1000FULL; adv |= ADVERTISE_1000FULL;
if (adv != oldadv) {
err = phy_write(phydev, MII_CTRL1000, adv); err = phy_write(phydev, MII_CTRL1000, adv);
if (err < 0) if (err < 0)
return err; return err;
changed = 1;
}
} }
return adv; return changed;
} }
EXPORT_SYMBOL(genphy_config_advert); EXPORT_SYMBOL(genphy_config_advert);
...@@ -561,19 +569,22 @@ int genphy_restart_aneg(struct phy_device *phydev) ...@@ -561,19 +569,22 @@ int genphy_restart_aneg(struct phy_device *phydev)
*/ */
int genphy_config_aneg(struct phy_device *phydev) int genphy_config_aneg(struct phy_device *phydev)
{ {
int err = 0; int result = 0;
if (AUTONEG_ENABLE == phydev->autoneg) { if (AUTONEG_ENABLE == phydev->autoneg) {
err = genphy_config_advert(phydev); int result = genphy_config_advert(phydev);
if (err < 0) if (result < 0) /* error */
return err; return result;
err = genphy_restart_aneg(phydev); /* Only restart aneg if we are advertising something different
* than we were before. */
if (result > 0)
result = genphy_restart_aneg(phydev);
} else } else
err = genphy_setup_forced(phydev); result = genphy_setup_forced(phydev);
return err; return result;
} }
EXPORT_SYMBOL(genphy_config_aneg); EXPORT_SYMBOL(genphy_config_aneg);
......
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