diff options
Diffstat (limited to 'drivers/net/phy/phy.c')
| -rw-r--r-- | drivers/net/phy/phy.c | 68 | 
1 files changed, 23 insertions, 45 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 6b0f89369b46..7c92afd36bbe 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -525,6 +525,12 @@ static int phy_check_link_status(struct phy_device *phydev)  	WARN_ON(!mutex_is_locked(&phydev->lock)); +	/* Keep previous state if loopback is enabled because some PHYs +	 * report that Link is Down when loopback is enabled. +	 */ +	if (phydev->loopback_enabled) +		return 0; +  	err = phy_read_status(phydev);  	if (err)  		return err; @@ -608,38 +614,21 @@ static int phy_poll_aneg_done(struct phy_device *phydev)   */  int phy_speed_down(struct phy_device *phydev, bool sync)  { -	__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); -	__ETHTOOL_DECLARE_LINK_MODE_MASK(adv); +	__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_tmp);  	int ret;  	if (phydev->autoneg != AUTONEG_ENABLE)  		return 0; -	linkmode_copy(adv_old, phydev->advertising); -	linkmode_copy(adv, phydev->lp_advertising); -	linkmode_and(adv, adv, phydev->supported); - -	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, adv) || -	    linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, adv)) { -		linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, -				   phydev->advertising); -		linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, -				   phydev->advertising); -		linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, -				   phydev->advertising); -		linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, -				   phydev->advertising); -	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, -				     adv) || -		   linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, -				     adv)) { -		linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, -				   phydev->advertising); -		linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, -				   phydev->advertising); -	} +	linkmode_copy(adv_tmp, phydev->advertising); + +	ret = phy_speed_down_core(phydev); +	if (ret) +		return ret; + +	linkmode_copy(phydev->adv_old, adv_tmp); -	if (linkmode_equal(phydev->advertising, adv_old)) +	if (linkmode_equal(phydev->advertising, adv_tmp))  		return 0;  	ret = phy_config_aneg(phydev); @@ -658,30 +647,19 @@ EXPORT_SYMBOL_GPL(phy_speed_down);   */  int phy_speed_up(struct phy_device *phydev)  { -	__ETHTOOL_DECLARE_LINK_MODE_MASK(all_speeds) = { 0, }; -	__ETHTOOL_DECLARE_LINK_MODE_MASK(not_speeds); -	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported); -	__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); -	__ETHTOOL_DECLARE_LINK_MODE_MASK(speeds); - -	linkmode_copy(adv_old, phydev->advertising); +	__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_tmp);  	if (phydev->autoneg != AUTONEG_ENABLE)  		return 0; -	linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, all_speeds); -	linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, all_speeds); -	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, all_speeds); -	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, all_speeds); -	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, all_speeds); -	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, all_speeds); +	if (linkmode_empty(phydev->adv_old)) +		return 0; -	linkmode_andnot(not_speeds, adv_old, all_speeds); -	linkmode_copy(supported, phydev->supported); -	linkmode_and(speeds, supported, all_speeds); -	linkmode_or(phydev->advertising, not_speeds, speeds); +	linkmode_copy(adv_tmp, phydev->advertising); +	linkmode_copy(phydev->advertising, phydev->adv_old); +	linkmode_zero(phydev->adv_old); -	if (linkmode_equal(phydev->advertising, adv_old)) +	if (linkmode_equal(phydev->advertising, adv_tmp))  		return 0;  	return phy_config_aneg(phydev); @@ -939,8 +917,8 @@ void phy_state_machine(struct work_struct *work)  		if (phydev->link) {  			phydev->link = 0;  			phy_link_down(phydev, true); -			do_suspend = true;  		} +		do_suspend = true;  		break;  	}  |