diff options
| author | Trent Piepho <tpiepho@freescale.com> | 2008-11-19 15:52:41 -0800 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2008-11-19 15:52:41 -0800 | 
| commit | de339c2aa7fea18410b1abeab5674bfbd4073a63 (patch) | |
| tree | 07b2d6c08d5fa9b3400fc00a286654dd06b5461a | |
| parent | 31c221c49f92d17632e0d662eb62a27e8b425805 (diff) | |
phylib: Fix auto-negotiation restart avoidance
A previous patch, 51e2a3846eab18711f4eb59cd0a4c33054e2980a, made
genphy_config_aneg() not restart aneg by calling genphy_restart_aneg() if
the advertisement hadn't changed.
But, genphy_restart_aneg() doesn't just restart aneg, it may also *enable*
aneg or un-isolate the PHY from the MII (those functions are controlled by
the same register).  The code to avoid calling genphy_restart_aneg() didn't
consider this.
So, modify genphy_config_aneg() to also check if the PHY needs to have aneg
enabled or be un-isolated before deciding not to restart aneg.
This caused a problem with certain Davicom PHYs, as that driver isolates
the PHY (why?) before calling genphy_config_aneg() and expects the PHY to
be un-isolated by that function.
Signed-off-by: Trent Piepho <tpiepho@freescale.com>
Reported-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/phy/phy_device.c | 34 | 
1 files changed, 23 insertions, 11 deletions
| diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 8fb1faca883a..55bc24b234e3 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -564,20 +564,32 @@ EXPORT_SYMBOL(genphy_restart_aneg);   */  int genphy_config_aneg(struct phy_device *phydev)  { -	int result = 0; +	int result; -	if (AUTONEG_ENABLE == phydev->autoneg) { -		int result = genphy_config_advert(phydev); +	if (AUTONEG_ENABLE != phydev->autoneg) +		return genphy_setup_forced(phydev); + +	result = genphy_config_advert(phydev); + +	if (result < 0) /* error */ +		return result; -		if (result < 0) /* error */ -			return result; +	if (result == 0) { +		/* Advertisment hasn't changed, but maybe aneg was never on to +		 * begin with?  Or maybe phy was isolated? */ +		int ctl = phy_read(phydev, MII_BMCR); + +		if (ctl < 0) +			return ctl; + +		if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) +			result = 1; /* do restart aneg */ +	} -		/* Only restart aneg if we are advertising something different -		 * than we were before.	 */ -		if (result > 0) -			result = genphy_restart_aneg(phydev); -	} else -		result = genphy_setup_forced(phydev); +	/* Only restart aneg if we are advertising something different +	 * than we were before.	 */ +	if (result > 0) +		result = genphy_restart_aneg(phydev);  	return result;  } | 
