diff options
author | Heiner Kallweit <hkallweit1@gmail.com> | 2019-08-12 17:51:27 -0400 |
---|---|---|
committer | Jakub Kicinski <jakub.kicinski@netronome.com> | 2019-08-13 20:14:06 -0400 |
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) | |||
315 | } | 315 | } |
316 | EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode); | 316 | EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode); |
317 | 317 | ||
318 | static int phy_resolve_min_speed(struct phy_device *phydev, bool fdx_only) | ||
319 | { | ||
320 | __ETHTOOL_DECLARE_LINK_MODE_MASK(common); | ||
321 | int i = ARRAY_SIZE(settings); | ||
322 | |||
323 | linkmode_and(common, phydev->lp_advertising, phydev->advertising); | ||
324 | |||
325 | while (--i >= 0) { | ||
326 | if (test_bit(settings[i].bit, common)) { | ||
327 | if (fdx_only && settings[i].duplex != DUPLEX_FULL) | ||
328 | continue; | ||
329 | return settings[i].speed; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | return SPEED_UNKNOWN; | ||
334 | } | ||
335 | |||
336 | int phy_speed_down_core(struct phy_device *phydev) | ||
337 | { | ||
338 | int min_common_speed = phy_resolve_min_speed(phydev, true); | ||
339 | |||
340 | if (min_common_speed == SPEED_UNKNOWN) | ||
341 | return -EINVAL; | ||
342 | |||
343 | return __set_linkmode_max_speed(min_common_speed, phydev->advertising); | ||
344 | } | ||
345 | |||
318 | static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad, | 346 | static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad, |
319 | u16 regnum) | 347 | u16 regnum) |
320 | { | 348 | { |
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, | |||
665 | unsigned long *mask); | 665 | unsigned long *mask); |
666 | void of_set_phy_supported(struct phy_device *phydev); | 666 | void of_set_phy_supported(struct phy_device *phydev); |
667 | void of_set_phy_eee_broken(struct phy_device *phydev); | 667 | void of_set_phy_eee_broken(struct phy_device *phydev); |
668 | int phy_speed_down_core(struct phy_device *phydev); | ||
668 | 669 | ||
669 | /** | 670 | /** |
670 | * phy_is_started - Convenience function to check whether PHY is started | 671 | * phy_is_started - Convenience function to check whether PHY is started |