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>
This commit is contained in:
parent
d2d37444e5
commit
a4eaed9f9a
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue