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/export.h>
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
const char *phy_speed_to_str(int speed)
|
const char *phy_speed_to_str(int speed)
|
||||||
{
|
{
|
||||||
|
@ -338,6 +339,50 @@ size_t phy_speeds(unsigned int *speeds, size_t size,
|
||||||
return count;
|
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
|
* phy_resolve_aneg_linkmode - resolve the advertisements into phy settings
|
||||||
* @phydev: The phy_device struct
|
* @phydev: The phy_device struct
|
||||||
|
|
|
@ -1949,44 +1949,6 @@ int genphy_loopback(struct phy_device *phydev, bool enable)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(genphy_loopback);
|
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
|
* phy_remove_link_mode - Remove a supported link mode
|
||||||
* @phydev: phy_device structure to remove link mode from
|
* @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);
|
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)
|
static void of_set_phy_eee_broken(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
struct device_node *node = phydev->mdio.dev.of_node;
|
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);
|
bool exact);
|
||||||
size_t phy_speeds(unsigned int *speeds, size_t size,
|
size_t phy_speeds(unsigned int *speeds, size_t size,
|
||||||
unsigned long *mask);
|
unsigned long *mask);
|
||||||
|
void of_set_phy_supported(struct phy_device *phydev);
|
||||||
|
|
||||||
static inline bool __phy_is_started(struct phy_device *phydev)
|
static inline bool __phy_is_started(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue