Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net-phy-let-phy_speed_down-up-support-speeds-1Gbps'

Heiner says:

====================
So far phy_speed_down/up can be used up to 1Gbps only. Remove this
restriction and add needed helpers to phy-core.c

v2:
- remove unused parameter in patch 1
- rename __phy_speed_down to phy_speed_down_core in patch 2
====================

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>

+53 -45
+35 -2
drivers/net/phy/phy-core.c
··· 207 207 return count; 208 208 } 209 209 210 - static int __set_phy_supported(struct phy_device *phydev, u32 max_speed) 210 + static int __set_linkmode_max_speed(u32 max_speed, unsigned long *addr) 211 211 { 212 212 const struct phy_setting *p; 213 213 int i; 214 214 215 215 for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) { 216 216 if (p->speed > max_speed) 217 - linkmode_clear_bit(p->bit, phydev->supported); 217 + linkmode_clear_bit(p->bit, addr); 218 218 else 219 219 break; 220 220 } 221 221 222 222 return 0; 223 + } 224 + 225 + static int __set_phy_supported(struct phy_device *phydev, u32 max_speed) 226 + { 227 + return __set_linkmode_max_speed(max_speed, phydev->supported); 223 228 } 224 229 225 230 int phy_set_max_speed(struct phy_device *phydev, u32 max_speed) ··· 314 309 } 315 310 } 316 311 EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode); 312 + 313 + static int phy_resolve_min_speed(struct phy_device *phydev, bool fdx_only) 314 + { 315 + __ETHTOOL_DECLARE_LINK_MODE_MASK(common); 316 + int i = ARRAY_SIZE(settings); 317 + 318 + linkmode_and(common, phydev->lp_advertising, phydev->advertising); 319 + 320 + while (--i >= 0) { 321 + if (test_bit(settings[i].bit, common)) { 322 + if (fdx_only && settings[i].duplex != DUPLEX_FULL) 323 + continue; 324 + return settings[i].speed; 325 + } 326 + } 327 + 328 + return SPEED_UNKNOWN; 329 + } 330 + 331 + int phy_speed_down_core(struct phy_device *phydev) 332 + { 333 + int min_common_speed = phy_resolve_min_speed(phydev, true); 334 + 335 + if (min_common_speed == SPEED_UNKNOWN) 336 + return -EINVAL; 337 + 338 + return __set_linkmode_max_speed(min_common_speed, phydev->advertising); 339 + } 317 340 318 341 static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad, 319 342 u16 regnum)
+15 -43
drivers/net/phy/phy.c
··· 608 608 */ 609 609 int phy_speed_down(struct phy_device *phydev, bool sync) 610 610 { 611 - __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); 612 - __ETHTOOL_DECLARE_LINK_MODE_MASK(adv); 611 + __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_tmp); 613 612 int ret; 614 613 615 614 if (phydev->autoneg != AUTONEG_ENABLE) 616 615 return 0; 617 616 618 - linkmode_copy(adv_old, phydev->advertising); 619 - linkmode_copy(adv, phydev->lp_advertising); 620 - linkmode_and(adv, adv, phydev->supported); 617 + linkmode_copy(adv_tmp, phydev->advertising); 621 618 622 - if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, adv) || 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 - } 619 + ret = phy_speed_down_core(phydev); 620 + if (ret) 621 + return ret; 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 626 return 0; 644 627 645 628 ret = phy_config_aneg(phydev); ··· 641 658 */ 642 659 int phy_speed_up(struct phy_device *phydev) 643 660 { 644 - __ETHTOOL_DECLARE_LINK_MODE_MASK(all_speeds) = { 0, }; 645 - __ETHTOOL_DECLARE_LINK_MODE_MASK(not_speeds); 646 - __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); 647 - __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); 648 - __ETHTOOL_DECLARE_LINK_MODE_MASK(speeds); 649 - 650 - linkmode_copy(adv_old, phydev->advertising); 661 + __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_tmp); 651 662 652 663 if (phydev->autoneg != AUTONEG_ENABLE) 653 664 return 0; 654 665 655 - linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, all_speeds); 656 - linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, all_speeds); 657 - linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, all_speeds); 658 - linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, all_speeds); 659 - linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, all_speeds); 660 - linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, all_speeds); 666 + if (linkmode_empty(phydev->adv_old)) 667 + return 0; 661 668 662 - linkmode_andnot(not_speeds, adv_old, all_speeds); 663 - linkmode_copy(supported, phydev->supported); 664 - linkmode_and(speeds, supported, all_speeds); 665 - linkmode_or(phydev->advertising, not_speeds, speeds); 669 + linkmode_copy(adv_tmp, phydev->advertising); 670 + linkmode_copy(phydev->advertising, phydev->adv_old); 671 + linkmode_zero(phydev->adv_old); 666 672 667 - if (linkmode_equal(phydev->advertising, adv_old)) 673 + if (linkmode_equal(phydev->advertising, adv_tmp)) 668 674 return 0; 669 675 670 676 return phy_config_aneg(phydev);
+3
include/linux/phy.h
··· 403 403 __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); 404 404 __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); 405 405 __ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising); 406 + /* used with phy_speed_down */ 407 + __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); 406 408 407 409 /* Energy efficient ethernet modes which should be prohibited */ 408 410 u32 eee_broken_modes; ··· 667 665 unsigned long *mask); 668 666 void of_set_phy_supported(struct phy_device *phydev); 669 667 void of_set_phy_eee_broken(struct phy_device *phydev); 668 + int phy_speed_down_core(struct phy_device *phydev); 670 669 671 670 /** 672 671 * phy_is_started - Convenience function to check whether PHY is started