diff options
author | Heiner Kallweit <hkallweit1@gmail.com> | 2019-08-12 23:51:27 +0200 |
---|---|---|
committer | Jakub Kicinski <jakub.kicinski@netronome.com> | 2019-08-13 17:14:06 -0700 |
commit | 331c56ac73846fa267c04ee6aa9a00bb5fed9440 (patch) | |
tree | fa890b319ae331f0fd04794b169702c610537fbd | |
parent | 7b261e0ef5f88087765df7f079a4bd0d285f7579 (diff) |
net: phy: add phy_speed_down_core and phy_resolve_min_speed
phy_speed_down_core provides most of the functionality for
phy_speed_down. It makes use of new helper phy_resolve_min_speed that is
based on the sorting of the settings[] array. In certain cases it may be
helpful to be able to exclude legacy half duplex modes, therefore
prepare phy_resolve_min_speed() for it.
v2:
- rename __phy_speed_down to phy_speed_down_core
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
-rw-r--r-- | drivers/net/phy/phy-core.c | 28 | ||||
-rw-r--r-- | include/linux/phy.h | 1 |
2 files changed, 29 insertions, 0 deletions
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 95f1e85d0d87..369903d9b6ec 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -315,6 +315,34 @@ void phy_resolve_aneg_linkmode(struct phy_device *phydev) } EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode); +static int phy_resolve_min_speed(struct phy_device *phydev, bool fdx_only) +{ + __ETHTOOL_DECLARE_LINK_MODE_MASK(common); + int i = ARRAY_SIZE(settings); + + linkmode_and(common, phydev->lp_advertising, phydev->advertising); + + while (--i >= 0) { + if (test_bit(settings[i].bit, common)) { + if (fdx_only && settings[i].duplex != DUPLEX_FULL) + continue; + return settings[i].speed; + } + } + + return SPEED_UNKNOWN; +} + +int phy_speed_down_core(struct phy_device *phydev) +{ + int min_common_speed = phy_resolve_min_speed(phydev, true); + + if (min_common_speed == SPEED_UNKNOWN) + return -EINVAL; + + return __set_linkmode_max_speed(min_common_speed, phydev->advertising); +} + static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad, u16 regnum) { diff --git a/include/linux/phy.h b/include/linux/phy.h index 781f4810ceba..62fdc7ff2b24 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -665,6 +665,7 @@ size_t phy_speeds(unsigned int *speeds, size_t size, unsigned long *mask); void of_set_phy_supported(struct phy_device *phydev); void of_set_phy_eee_broken(struct phy_device *phydev); +int phy_speed_down_core(struct phy_device *phydev); /** * phy_is_started - Convenience function to check whether PHY is started |