net: phy: Mask-out non-compatible modes when setting the max-speed
authorMaxime Chevallier <maxime.chevallier@bootlin.com>
Mon, 11 Feb 2019 14:25:26 +0000 (15:25 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 14 Feb 2019 00:17:53 +0000 (19:17 -0500)
When setting a PHY's max speed using either the max-speed DT property
or ethtool, we should mask-out all non-compatible modes according to the
settings table, instead of just the 10/100BASET modes.

Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Suggested-by: Russell King <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/phy-core.c
drivers/net/phy/phy_device.c
include/linux/phy.h

index cdea028d13284648d305c3ffeb90da5240080213..855abf487279c9ca957513ae6a4632ed88b59718 100644 (file)
@@ -4,6 +4,7 @@
  */
 #include <linux/export.h>
 #include <linux/phy.h>
+#include <linux/of.h>
 
 const char *phy_speed_to_str(int speed)
 {
@@ -338,6 +339,50 @@ size_t phy_speeds(unsigned int *speeds, size_t size,
        return count;
 }
 
+static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
+{
+       const struct phy_setting *p;
+       int i;
+
+       for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
+               if (p->speed > max_speed)
+                       linkmode_clear_bit(p->bit, phydev->supported);
+               else
+                       break;
+       }
+
+       return 0;
+}
+
+int phy_set_max_speed(struct phy_device *phydev, u32 max_speed)
+{
+       int err;
+
+       err = __set_phy_supported(phydev, max_speed);
+       if (err)
+               return err;
+
+       linkmode_copy(phydev->advertising, phydev->supported);
+
+       return 0;
+}
+EXPORT_SYMBOL(phy_set_max_speed);
+
+void of_set_phy_supported(struct phy_device *phydev)
+{
+       struct device_node *node = phydev->mdio.dev.of_node;
+       u32 max_speed;
+
+       if (!IS_ENABLED(CONFIG_OF_MDIO))
+               return;
+
+       if (!node)
+               return;
+
+       if (!of_property_read_u32(node, "max-speed", &max_speed))
+               __set_phy_supported(phydev, max_speed);
+}
+
 /**
  * phy_resolve_aneg_linkmode - resolve the advertisements into phy settings
  * @phydev: The phy_device struct
index 2c61282a272616395a55d6440ddbbfc3ad5aa638..64497ec293e12d6ea53f59b8bc69c9c4570540b2 100644 (file)
@@ -1949,44 +1949,6 @@ int genphy_loopback(struct phy_device *phydev, bool enable)
 }
 EXPORT_SYMBOL(genphy_loopback);
 
-static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
-{
-       switch (max_speed) {
-       case SPEED_10:
-               linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
-                                  phydev->supported);
-               linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
-                                  phydev->supported);
-               /* fall through */
-       case SPEED_100:
-               linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
-                                  phydev->supported);
-               linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
-                                  phydev->supported);
-               break;
-       case SPEED_1000:
-               break;
-       default:
-               return -ENOTSUPP;
-       }
-
-       return 0;
-}
-
-int phy_set_max_speed(struct phy_device *phydev, u32 max_speed)
-{
-       int err;
-
-       err = __set_phy_supported(phydev, max_speed);
-       if (err)
-               return err;
-
-       linkmode_copy(phydev->advertising, phydev->supported);
-
-       return 0;
-}
-EXPORT_SYMBOL(phy_set_max_speed);
-
 /**
  * phy_remove_link_mode - Remove a supported link mode
  * @phydev: phy_device structure to remove link mode from
@@ -2117,21 +2079,6 @@ bool phy_validate_pause(struct phy_device *phydev,
 }
 EXPORT_SYMBOL(phy_validate_pause);
 
-static void of_set_phy_supported(struct phy_device *phydev)
-{
-       struct device_node *node = phydev->mdio.dev.of_node;
-       u32 max_speed;
-
-       if (!IS_ENABLED(CONFIG_OF_MDIO))
-               return;
-
-       if (!node)
-               return;
-
-       if (!of_property_read_u32(node, "max-speed", &max_speed))
-               __set_phy_supported(phydev, max_speed);
-}
-
 static void of_set_phy_eee_broken(struct phy_device *phydev)
 {
        struct device_node *node = phydev->mdio.dev.of_node;
index 378da9a6165e7a50efa81edf4d37bca8e55efe91..20344c7744d8546e16bc8d717cce1516dbc56f75 100644 (file)
@@ -673,6 +673,7 @@ phy_lookup_setting(int speed, int duplex, const unsigned long *mask,
                   bool exact);
 size_t phy_speeds(unsigned int *speeds, size_t size,
                  unsigned long *mask);
+void of_set_phy_supported(struct phy_device *phydev);
 
 static inline bool __phy_is_started(struct phy_device *phydev)
 {