aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiner Kallweit <hkallweit1@gmail.com>2019-08-12 17:51:27 -0400
committerJakub Kicinski <jakub.kicinski@netronome.com>2019-08-13 20:14:06 -0400
commit331c56ac73846fa267c04ee6aa9a00bb5fed9440 (patch)
treefa890b319ae331f0fd04794b169702c610537fbd
parent7b261e0ef5f88087765df7f079a4bd0d285f7579 (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.c28
-rw-r--r--include/linux/phy.h1
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}
316EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode); 316EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode);
317 317
318static 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
336int 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
318static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad, 346static 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);
666void of_set_phy_supported(struct phy_device *phydev); 666void of_set_phy_supported(struct phy_device *phydev);
667void of_set_phy_eee_broken(struct phy_device *phydev); 667void of_set_phy_eee_broken(struct phy_device *phydev);
668int 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