diff options
author | Heiner Kallweit <hkallweit1@gmail.com> | 2019-08-12 17:52:19 -0400 |
---|---|---|
committer | Jakub Kicinski <jakub.kicinski@netronome.com> | 2019-08-13 20:14:06 -0400 |
commit | 65b27995a4ab8fc51b4adc6b4dcdca20f7a595bb (patch) | |
tree | 7b8814cf8b7bd2767af3c3080b20c9b9c4a2b70f /drivers/net/phy/phy.c | |
parent | 331c56ac73846fa267c04ee6aa9a00bb5fed9440 (diff) |
net: phy: let phy_speed_down/up support speeds >1Gbps
So far phy_speed_down/up can be used up to 1Gbps only. Remove this
restriction by using new helper __phy_speed_down. New member adv_old
in struct phy_device is used by phy_speed_up to restore the advertised
modes before calling phy_speed_down. Don't simply advertise what is
supported because a user may have intentionally removed modes from
advertisement.
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Diffstat (limited to 'drivers/net/phy/phy.c')
-rw-r--r-- | drivers/net/phy/phy.c | 60 |
1 files changed, 16 insertions, 44 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index ef7aa738e0dc..f3adea9ef400 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c | |||
@@ -608,38 +608,21 @@ static int phy_poll_aneg_done(struct phy_device *phydev) | |||
608 | */ | 608 | */ |
609 | int phy_speed_down(struct phy_device *phydev, bool sync) | 609 | int phy_speed_down(struct phy_device *phydev, bool sync) |
610 | { | 610 | { |
611 | __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); | 611 | __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_tmp); |
612 | __ETHTOOL_DECLARE_LINK_MODE_MASK(adv); | ||
613 | int ret; | 612 | int ret; |
614 | 613 | ||
615 | if (phydev->autoneg != AUTONEG_ENABLE) | 614 | if (phydev->autoneg != AUTONEG_ENABLE) |
616 | return 0; | 615 | return 0; |
617 | 616 | ||
618 | linkmode_copy(adv_old, phydev->advertising); | 617 | linkmode_copy(adv_tmp, phydev->advertising); |
619 | linkmode_copy(adv, phydev->lp_advertising); | 618 | |
620 | linkmode_and(adv, adv, phydev->supported); | 619 | ret = phy_speed_down_core(phydev); |
621 | 620 | if (ret) | |
622 | if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, adv) || | 621 | return ret; |
623 | linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, adv)) { | ||
624 | linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, | ||
625 | phydev->advertising); | ||
626 | linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, | ||
627 | phydev->advertising); | ||
628 | linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, | ||
629 | phydev->advertising); | ||
630 | linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, | ||
631 | phydev->advertising); | ||
632 | } else if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, | ||
633 | adv) || | ||
634 | linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, | ||
635 | adv)) { | ||
636 | linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, | ||
637 | phydev->advertising); | ||
638 | linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, | ||
639 | phydev->advertising); | ||
640 | } | ||
641 | 622 | ||
642 | if (linkmode_equal(phydev->advertising, adv_old)) | 623 | linkmode_copy(phydev->adv_old, adv_tmp); |
624 | |||
625 | if (linkmode_equal(phydev->advertising, adv_tmp)) | ||
643 | return 0; | 626 | return 0; |
644 | 627 | ||
645 | ret = phy_config_aneg(phydev); | 628 | ret = phy_config_aneg(phydev); |
@@ -658,30 +641,19 @@ EXPORT_SYMBOL_GPL(phy_speed_down); | |||
658 | */ | 641 | */ |
659 | int phy_speed_up(struct phy_device *phydev) | 642 | int phy_speed_up(struct phy_device *phydev) |
660 | { | 643 | { |
661 | __ETHTOOL_DECLARE_LINK_MODE_MASK(all_speeds) = { 0, }; | 644 | __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_tmp); |
662 | __ETHTOOL_DECLARE_LINK_MODE_MASK(not_speeds); | ||
663 | __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); | ||
664 | __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); | ||
665 | __ETHTOOL_DECLARE_LINK_MODE_MASK(speeds); | ||
666 | |||
667 | linkmode_copy(adv_old, phydev->advertising); | ||
668 | 645 | ||
669 | if (phydev->autoneg != AUTONEG_ENABLE) | 646 | if (phydev->autoneg != AUTONEG_ENABLE) |
670 | return 0; | 647 | return 0; |
671 | 648 | ||
672 | linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, all_speeds); | 649 | if (linkmode_empty(phydev->adv_old)) |
673 | linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, all_speeds); | 650 | return 0; |
674 | linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, all_speeds); | ||
675 | linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, all_speeds); | ||
676 | linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, all_speeds); | ||
677 | linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, all_speeds); | ||
678 | 651 | ||
679 | linkmode_andnot(not_speeds, adv_old, all_speeds); | 652 | linkmode_copy(adv_tmp, phydev->advertising); |
680 | linkmode_copy(supported, phydev->supported); | 653 | linkmode_copy(phydev->advertising, phydev->adv_old); |
681 | linkmode_and(speeds, supported, all_speeds); | 654 | linkmode_zero(phydev->adv_old); |
682 | linkmode_or(phydev->advertising, not_speeds, speeds); | ||
683 | 655 | ||
684 | if (linkmode_equal(phydev->advertising, adv_old)) | 656 | if (linkmode_equal(phydev->advertising, adv_tmp)) |
685 | return 0; | 657 | return 0; |
686 | 658 | ||
687 | return phy_config_aneg(phydev); | 659 | return phy_config_aneg(phydev); |