summaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/phy-core.c
diff options
context:
space:
mode:
authorMaxime Chevallier <maxime.chevallier@bootlin.com>2019-02-11 15:25:26 +0100
committerDavid S. Miller <davem@davemloft.net>2019-02-13 19:17:53 -0500
commita4eaed9f9a895b16bb2c54e0ff6b3c99404fec92 (patch)
tree013f32d19cbe10b62f226ac6268be347b3871087 /drivers/net/phy/phy-core.c
parentd2d37444e5603b9f6121905fab7d8e859ed0c59d (diff)
downloadlinux-stable-a4eaed9f9a895b16bb2c54e0ff6b3c99404fec92.tar.gz
linux-stable-a4eaed9f9a895b16bb2c54e0ff6b3c99404fec92.tar.bz2
linux-stable-a4eaed9f9a895b16bb2c54e0ff6b3c99404fec92.zip
net: phy: Mask-out non-compatible modes when setting the max-speed
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>
Diffstat (limited to 'drivers/net/phy/phy-core.c')
-rw-r--r--drivers/net/phy/phy-core.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index cdea028d1328..855abf487279 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -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