net: phy: add phy_speed_down_core and phy_resolve_min_speed
authorHeiner Kallweit <hkallweit1@gmail.com>
Mon, 12 Aug 2019 21:51:27 +0000 (23:51 +0200)
committerJakub Kicinski <jakub.kicinski@netronome.com>
Wed, 14 Aug 2019 00:14:06 +0000 (17:14 -0700)
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>
drivers/net/phy/phy-core.c
include/linux/phy.h

index 95f1e85d0d87d209317fb8ecd7a92a23922c0832..369903d9b6eceba076ba295b80a28fed700297ed 100644 (file)
@@ -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)
 {
index 781f4810cebaf385716a3c48ad37089c6534bde5..62fdc7ff2b24b0f2fdc82bb9f08bdde5e9c3d076 100644 (file)
@@ -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