net: ethernet: Convert phydev advertize and supported from u32 to link mode
There are a few MAC/PHYs combinations which now support > 1Gbps. These may need to make use of link modes with bits > 31. Thus their supported PHY features or advertised features cannot be implemented using the current bitmap in a u32. Convert to using a linkmode bitmap, which can support all the currently devices link modes, and is future proof as more modes are added. Signed-off-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Esse commit está contido em:
@@ -25,15 +25,10 @@
|
||||
#define PHY_ID_AQR107 0x03a1b4e0
|
||||
#define PHY_ID_AQR405 0x03a1b4b0
|
||||
|
||||
#define PHY_AQUANTIA_FEATURES (SUPPORTED_10000baseT_Full | \
|
||||
SUPPORTED_1000baseT_Full | \
|
||||
SUPPORTED_100baseT_Full | \
|
||||
PHY_DEFAULT_FEATURES)
|
||||
|
||||
static int aquantia_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
phydev->supported = PHY_AQUANTIA_FEATURES;
|
||||
phydev->advertising = phydev->supported;
|
||||
linkmode_copy(phydev->supported, phy_10gbit_features);
|
||||
linkmode_copy(phydev->advertising, phydev->supported);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -43,7 +43,7 @@ static int bcm63xx_config_init(struct phy_device *phydev)
|
||||
int reg, err;
|
||||
|
||||
/* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
|
||||
phydev->supported |= SUPPORTED_Pause;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);
|
||||
|
||||
reg = phy_read(phydev, MII_BCM63XX_IR);
|
||||
if (reg < 0)
|
||||
|
@@ -86,8 +86,12 @@ static int bcm87xx_of_reg_init(struct phy_device *phydev)
|
||||
|
||||
static int bcm87xx_config_init(struct phy_device *phydev)
|
||||
{
|
||||
phydev->supported = SUPPORTED_10000baseR_FEC;
|
||||
phydev->advertising = ADVERTISED_10000baseR_FEC;
|
||||
linkmode_zero(phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
|
||||
phydev->supported);
|
||||
linkmode_zero(phydev->advertising);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
|
||||
phydev->advertising);
|
||||
phydev->state = PHY_NOLINK;
|
||||
phydev->autoneg = AUTONEG_DISABLE;
|
||||
|
||||
|
@@ -223,14 +223,23 @@ struct phy_device *fixed_phy_register(unsigned int irq,
|
||||
|
||||
switch (status->speed) {
|
||||
case SPEED_1000:
|
||||
phy->supported = PHY_1000BT_FEATURES;
|
||||
break;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
phy->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
phy->supported);
|
||||
/* fall through */
|
||||
case SPEED_100:
|
||||
phy->supported = PHY_100BT_FEATURES;
|
||||
break;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
||||
phy->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
phy->supported);
|
||||
/* fall through */
|
||||
case SPEED_10:
|
||||
default:
|
||||
phy->supported = PHY_10BT_FEATURES;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
|
||||
phy->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
|
||||
phy->supported);
|
||||
}
|
||||
|
||||
ret = phy_device_register(phy);
|
||||
|
@@ -491,25 +491,26 @@ static int m88e1318_config_aneg(struct phy_device *phydev)
|
||||
}
|
||||
|
||||
/**
|
||||
* ethtool_adv_to_fiber_adv_t
|
||||
* @ethadv: the ethtool advertisement settings
|
||||
* linkmode_adv_to_fiber_adv_t
|
||||
* @advertise: the linkmode advertisement settings
|
||||
*
|
||||
* A small helper function that translates ethtool advertisement
|
||||
* settings to phy autonegotiation advertisements for the
|
||||
* MII_ADV register for fiber link.
|
||||
* A small helper function that translates linkmode advertisement
|
||||
* settings to phy autonegotiation advertisements for the MII_ADV
|
||||
* register for fiber link.
|
||||
*/
|
||||
static inline u32 ethtool_adv_to_fiber_adv_t(u32 ethadv)
|
||||
static inline u32 linkmode_adv_to_fiber_adv_t(unsigned long *advertise)
|
||||
{
|
||||
u32 result = 0;
|
||||
|
||||
if (ethadv & ADVERTISED_1000baseT_Half)
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertise))
|
||||
result |= ADVERTISE_FIBER_1000HALF;
|
||||
if (ethadv & ADVERTISED_1000baseT_Full)
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertise))
|
||||
result |= ADVERTISE_FIBER_1000FULL;
|
||||
|
||||
if ((ethadv & ADVERTISE_PAUSE_ASYM) && (ethadv & ADVERTISE_PAUSE_CAP))
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertise) &&
|
||||
linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))
|
||||
result |= LPA_PAUSE_ASYM_FIBER;
|
||||
else if (ethadv & ADVERTISE_PAUSE_CAP)
|
||||
else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))
|
||||
result |= (ADVERTISE_PAUSE_FIBER
|
||||
& (~ADVERTISE_PAUSE_ASYM_FIBER));
|
||||
|
||||
@@ -530,14 +531,13 @@ static int marvell_config_aneg_fiber(struct phy_device *phydev)
|
||||
int changed = 0;
|
||||
int err;
|
||||
int adv, oldadv;
|
||||
u32 advertise;
|
||||
|
||||
if (phydev->autoneg != AUTONEG_ENABLE)
|
||||
return genphy_setup_forced(phydev);
|
||||
|
||||
/* Only allow advertising what this PHY supports */
|
||||
phydev->advertising &= phydev->supported;
|
||||
advertise = phydev->advertising;
|
||||
linkmode_and(phydev->advertising, phydev->advertising,
|
||||
phydev->supported);
|
||||
|
||||
/* Setup fiber advertisement */
|
||||
adv = phy_read(phydev, MII_ADVERTISE);
|
||||
@@ -547,7 +547,7 @@ static int marvell_config_aneg_fiber(struct phy_device *phydev)
|
||||
oldadv = adv;
|
||||
adv &= ~(ADVERTISE_FIBER_1000HALF | ADVERTISE_FIBER_1000FULL
|
||||
| LPA_PAUSE_FIBER);
|
||||
adv |= ethtool_adv_to_fiber_adv_t(advertise);
|
||||
adv |= linkmode_adv_to_fiber_adv_t(phydev->advertising);
|
||||
|
||||
if (adv != oldadv) {
|
||||
err = phy_write(phydev, MII_ADVERTISE, adv);
|
||||
@@ -879,8 +879,14 @@ static int m88e1510_config_init(struct phy_device *phydev)
|
||||
* so disable Pause support.
|
||||
*/
|
||||
pause = SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
phydev->supported &= ~pause;
|
||||
phydev->advertising &= ~pause;
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->supported);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->supported);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->advertising);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->advertising);
|
||||
}
|
||||
|
||||
return m88e1318_config_init(phydev);
|
||||
@@ -1235,7 +1241,8 @@ static int marvell_read_status(struct phy_device *phydev)
|
||||
int err;
|
||||
|
||||
/* Check the fiber mode first */
|
||||
if (phydev->supported & SUPPORTED_FIBRE &&
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
|
||||
phydev->supported) &&
|
||||
phydev->interface != PHY_INTERFACE_MODE_SGMII) {
|
||||
err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
|
||||
if (err < 0)
|
||||
@@ -1278,7 +1285,8 @@ static int marvell_suspend(struct phy_device *phydev)
|
||||
int err;
|
||||
|
||||
/* Suspend the fiber mode first */
|
||||
if (!(phydev->supported & SUPPORTED_FIBRE)) {
|
||||
if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
|
||||
phydev->supported)) {
|
||||
err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
@@ -1312,7 +1320,8 @@ static int marvell_resume(struct phy_device *phydev)
|
||||
int err;
|
||||
|
||||
/* Resume the fiber mode first */
|
||||
if (!(phydev->supported & SUPPORTED_FIBRE)) {
|
||||
if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
|
||||
phydev->supported)) {
|
||||
err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
@@ -1463,7 +1472,8 @@ error:
|
||||
|
||||
static int marvell_get_sset_count(struct phy_device *phydev)
|
||||
{
|
||||
if (phydev->supported & SUPPORTED_FIBRE)
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
|
||||
phydev->supported))
|
||||
return ARRAY_SIZE(marvell_hw_stats);
|
||||
else
|
||||
return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS;
|
||||
|
@@ -252,7 +252,6 @@ static int mv3310_resume(struct phy_device *phydev)
|
||||
static int mv3310_config_init(struct phy_device *phydev)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
|
||||
u32 mask;
|
||||
int val;
|
||||
|
||||
/* Check that the PHY interface type is compatible */
|
||||
@@ -336,13 +335,9 @@ static int mv3310_config_init(struct phy_device *phydev)
|
||||
}
|
||||
}
|
||||
|
||||
if (!ethtool_convert_link_mode_to_legacy_u32(&mask, supported))
|
||||
phydev_warn(phydev,
|
||||
"PHY supports (%*pb) more modes than phylib supports, some modes not supported.\n",
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS, supported);
|
||||
|
||||
phydev->supported &= mask;
|
||||
phydev->advertising &= phydev->supported;
|
||||
linkmode_copy(phydev->supported, supported);
|
||||
linkmode_and(phydev->advertising, phydev->advertising,
|
||||
phydev->supported);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -350,7 +345,7 @@ static int mv3310_config_init(struct phy_device *phydev)
|
||||
static int mv3310_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
bool changed = false;
|
||||
u32 advertising;
|
||||
u16 reg;
|
||||
int ret;
|
||||
|
||||
/* We don't support manual MDI control */
|
||||
@@ -364,31 +359,35 @@ static int mv3310_config_aneg(struct phy_device *phydev)
|
||||
return genphy_c45_an_disable_aneg(phydev);
|
||||
}
|
||||
|
||||
phydev->advertising &= phydev->supported;
|
||||
advertising = phydev->advertising;
|
||||
linkmode_and(phydev->advertising, phydev->advertising,
|
||||
phydev->supported);
|
||||
|
||||
ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE,
|
||||
ADVERTISE_ALL | ADVERTISE_100BASE4 |
|
||||
ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
|
||||
ethtool_adv_to_mii_adv_t(advertising));
|
||||
linkmode_adv_to_mii_adv_t(phydev->advertising));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
changed = true;
|
||||
|
||||
reg = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
|
||||
ret = mv3310_modify(phydev, MDIO_MMD_AN, MV_AN_CTRL1000,
|
||||
ADVERTISE_1000FULL | ADVERTISE_1000HALF,
|
||||
ethtool_adv_to_mii_ctrl1000_t(advertising));
|
||||
ADVERTISE_1000FULL | ADVERTISE_1000HALF, reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
changed = true;
|
||||
|
||||
/* 10G control register */
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
|
||||
phydev->advertising))
|
||||
reg = MDIO_AN_10GBT_CTRL_ADV10G;
|
||||
else
|
||||
reg = 0;
|
||||
|
||||
ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
|
||||
MDIO_AN_10GBT_CTRL_ADV10G,
|
||||
advertising & ADVERTISED_10000baseT_Full ?
|
||||
MDIO_AN_10GBT_CTRL_ADV10G : 0);
|
||||
MDIO_AN_10GBT_CTRL_ADV10G, reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
|
@@ -311,17 +311,22 @@ static int kszphy_config_init(struct phy_device *phydev)
|
||||
|
||||
static int ksz8041_config_init(struct phy_device *phydev)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
|
||||
|
||||
struct device_node *of_node = phydev->mdio.dev.of_node;
|
||||
|
||||
/* Limit supported and advertised modes in fiber mode */
|
||||
if (of_property_read_bool(of_node, "micrel,fiber-mode")) {
|
||||
phydev->dev_flags |= MICREL_PHY_FXEN;
|
||||
phydev->supported &= SUPPORTED_100baseT_Full |
|
||||
SUPPORTED_100baseT_Half;
|
||||
phydev->supported |= SUPPORTED_FIBRE;
|
||||
phydev->advertising &= ADVERTISED_100baseT_Full |
|
||||
ADVERTISED_100baseT_Half;
|
||||
phydev->advertising |= ADVERTISED_FIBRE;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, mask);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, mask);
|
||||
|
||||
linkmode_and(phydev->supported, phydev->supported, mask);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
|
||||
phydev->supported);
|
||||
linkmode_and(phydev->advertising, phydev->advertising, mask);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
|
||||
phydev->advertising);
|
||||
phydev->autoneg = AUTONEG_DISABLE;
|
||||
}
|
||||
|
||||
|
@@ -304,8 +304,11 @@ EXPORT_SYMBOL_GPL(gen10g_no_soft_reset);
|
||||
int gen10g_config_init(struct phy_device *phydev)
|
||||
{
|
||||
/* Temporarily just say we support everything */
|
||||
phydev->supported = SUPPORTED_10000baseT_Full;
|
||||
phydev->advertising = SUPPORTED_10000baseT_Full;
|
||||
linkmode_zero(phydev->supported);
|
||||
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
linkmode_copy(phydev->advertising, phydev->supported);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -129,7 +129,6 @@ static const struct phy_setting settings[] = {
|
||||
* @speed: speed to match
|
||||
* @duplex: duplex to match
|
||||
* @mask: allowed link modes
|
||||
* @maxbit: bit size of link modes
|
||||
* @exact: an exact match is required
|
||||
*
|
||||
* Search the settings array for a setting that matches the speed and
|
||||
@@ -143,14 +142,14 @@ static const struct phy_setting settings[] = {
|
||||
* they all fail, %NULL will be returned.
|
||||
*/
|
||||
const struct phy_setting *
|
||||
phy_lookup_setting(int speed, int duplex, const unsigned long *mask,
|
||||
size_t maxbit, bool exact)
|
||||
phy_lookup_setting(int speed, int duplex, const unsigned long *mask, bool exact)
|
||||
{
|
||||
const struct phy_setting *p, *match = NULL, *last = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
|
||||
if (p->bit < maxbit && test_bit(p->bit, mask)) {
|
||||
if (p->bit < __ETHTOOL_LINK_MODE_MASK_NBITS &&
|
||||
test_bit(p->bit, mask)) {
|
||||
last = p;
|
||||
if (p->speed == speed && p->duplex == duplex) {
|
||||
/* Exact match for speed and duplex */
|
||||
@@ -175,13 +174,13 @@ phy_lookup_setting(int speed, int duplex, const unsigned long *mask,
|
||||
EXPORT_SYMBOL_GPL(phy_lookup_setting);
|
||||
|
||||
size_t phy_speeds(unsigned int *speeds, size_t size,
|
||||
unsigned long *mask, size_t maxbit)
|
||||
unsigned long *mask)
|
||||
{
|
||||
size_t count;
|
||||
int i;
|
||||
|
||||
for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++)
|
||||
if (settings[i].bit < maxbit &&
|
||||
if (settings[i].bit < __ETHTOOL_LINK_MODE_MASK_NBITS &&
|
||||
test_bit(settings[i].bit, mask) &&
|
||||
(count == 0 || speeds[count - 1] != settings[i].speed))
|
||||
speeds[count++] = settings[i].speed;
|
||||
@@ -199,27 +198,38 @@ size_t phy_speeds(unsigned int *speeds, size_t size,
|
||||
*/
|
||||
void phy_resolve_aneg_linkmode(struct phy_device *phydev)
|
||||
{
|
||||
u32 common = phydev->lp_advertising & phydev->advertising;
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(common);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(lp);
|
||||
|
||||
if (common & ADVERTISED_10000baseT_Full) {
|
||||
ethtool_convert_legacy_u32_to_link_mode(lp, phydev->lp_advertising);
|
||||
|
||||
linkmode_and(common, lp, phydev->advertising);
|
||||
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, common)) {
|
||||
phydev->speed = SPEED_10000;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
} else if (common & ADVERTISED_1000baseT_Full) {
|
||||
} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
common)) {
|
||||
phydev->speed = SPEED_1000;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
} else if (common & ADVERTISED_1000baseT_Half) {
|
||||
} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
common)) {
|
||||
phydev->speed = SPEED_1000;
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
} else if (common & ADVERTISED_100baseT_Full) {
|
||||
} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
common)) {
|
||||
phydev->speed = SPEED_100;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
} else if (common & ADVERTISED_100baseT_Half) {
|
||||
} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
||||
common)) {
|
||||
phydev->speed = SPEED_100;
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
} else if (common & ADVERTISED_10baseT_Full) {
|
||||
} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
|
||||
common)) {
|
||||
phydev->speed = SPEED_10;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
} else if (common & ADVERTISED_10baseT_Half) {
|
||||
} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
|
||||
common)) {
|
||||
phydev->speed = SPEED_10;
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
}
|
||||
|
@@ -179,11 +179,9 @@ EXPORT_SYMBOL(phy_aneg_done);
|
||||
* settings were found.
|
||||
*/
|
||||
static const struct phy_setting *
|
||||
phy_find_valid(int speed, int duplex, u32 supported)
|
||||
phy_find_valid(int speed, int duplex, unsigned long *supported)
|
||||
{
|
||||
unsigned long mask = supported;
|
||||
|
||||
return phy_lookup_setting(speed, duplex, &mask, BITS_PER_LONG, false);
|
||||
return phy_lookup_setting(speed, duplex, supported, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,9 +198,7 @@ unsigned int phy_supported_speeds(struct phy_device *phy,
|
||||
unsigned int *speeds,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned long supported = phy->supported;
|
||||
|
||||
return phy_speeds(speeds, size, &supported, BITS_PER_LONG);
|
||||
return phy_speeds(speeds, size, phy->supported);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,11 +210,10 @@ unsigned int phy_supported_speeds(struct phy_device *phy,
|
||||
*
|
||||
* Description: Returns true if there is a valid setting, false otherwise.
|
||||
*/
|
||||
static inline bool phy_check_valid(int speed, int duplex, u32 features)
|
||||
static inline bool phy_check_valid(int speed, int duplex,
|
||||
unsigned long *features)
|
||||
{
|
||||
unsigned long mask = features;
|
||||
|
||||
return !!phy_lookup_setting(speed, duplex, &mask, BITS_PER_LONG, true);
|
||||
return !!phy_lookup_setting(speed, duplex, features, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,13 +227,13 @@ static inline bool phy_check_valid(int speed, int duplex, u32 features)
|
||||
static void phy_sanitize_settings(struct phy_device *phydev)
|
||||
{
|
||||
const struct phy_setting *setting;
|
||||
u32 features = phydev->supported;
|
||||
|
||||
/* Sanitize settings based on PHY capabilities */
|
||||
if ((features & SUPPORTED_Autoneg) == 0)
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported))
|
||||
phydev->autoneg = AUTONEG_DISABLE;
|
||||
|
||||
setting = phy_find_valid(phydev->speed, phydev->duplex, features);
|
||||
setting = phy_find_valid(phydev->speed, phydev->duplex,
|
||||
phydev->supported);
|
||||
if (setting) {
|
||||
phydev->speed = setting->speed;
|
||||
phydev->duplex = setting->duplex;
|
||||
@@ -264,13 +259,15 @@ static void phy_sanitize_settings(struct phy_device *phydev)
|
||||
*/
|
||||
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
|
||||
u32 speed = ethtool_cmd_speed(cmd);
|
||||
|
||||
if (cmd->phy_address != phydev->mdio.addr)
|
||||
return -EINVAL;
|
||||
|
||||
/* We make sure that we don't pass unsupported values in to the PHY */
|
||||
cmd->advertising &= phydev->supported;
|
||||
ethtool_convert_legacy_u32_to_link_mode(advertising, cmd->advertising);
|
||||
linkmode_and(advertising, advertising, phydev->supported);
|
||||
|
||||
/* Verify the settings we care about. */
|
||||
if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
|
||||
@@ -291,12 +288,14 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
|
||||
|
||||
phydev->speed = speed;
|
||||
|
||||
phydev->advertising = cmd->advertising;
|
||||
linkmode_copy(phydev->advertising, advertising);
|
||||
|
||||
if (AUTONEG_ENABLE == cmd->autoneg)
|
||||
phydev->advertising |= ADVERTISED_Autoneg;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
|
||||
phydev->advertising);
|
||||
else
|
||||
phydev->advertising &= ~ADVERTISED_Autoneg;
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
|
||||
phydev->advertising);
|
||||
|
||||
phydev->duplex = cmd->duplex;
|
||||
|
||||
@@ -312,19 +311,18 @@ EXPORT_SYMBOL(phy_ethtool_sset);
|
||||
int phy_ethtool_ksettings_set(struct phy_device *phydev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
|
||||
u8 autoneg = cmd->base.autoneg;
|
||||
u8 duplex = cmd->base.duplex;
|
||||
u32 speed = cmd->base.speed;
|
||||
u32 advertising;
|
||||
|
||||
if (cmd->base.phy_address != phydev->mdio.addr)
|
||||
return -EINVAL;
|
||||
|
||||
ethtool_convert_link_mode_to_legacy_u32(&advertising,
|
||||
cmd->link_modes.advertising);
|
||||
linkmode_copy(advertising, cmd->link_modes.advertising);
|
||||
|
||||
/* We make sure that we don't pass unsupported values in to the PHY */
|
||||
advertising &= phydev->supported;
|
||||
linkmode_and(advertising, advertising, phydev->supported);
|
||||
|
||||
/* Verify the settings we care about. */
|
||||
if (autoneg != AUTONEG_ENABLE && autoneg != AUTONEG_DISABLE)
|
||||
@@ -345,12 +343,14 @@ int phy_ethtool_ksettings_set(struct phy_device *phydev,
|
||||
|
||||
phydev->speed = speed;
|
||||
|
||||
phydev->advertising = advertising;
|
||||
linkmode_copy(phydev->advertising, advertising);
|
||||
|
||||
if (autoneg == AUTONEG_ENABLE)
|
||||
phydev->advertising |= ADVERTISED_Autoneg;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
|
||||
phydev->advertising);
|
||||
else
|
||||
phydev->advertising &= ~ADVERTISED_Autoneg;
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
|
||||
phydev->advertising);
|
||||
|
||||
phydev->duplex = duplex;
|
||||
|
||||
@@ -366,11 +366,8 @@ EXPORT_SYMBOL(phy_ethtool_ksettings_set);
|
||||
void phy_ethtool_ksettings_get(struct phy_device *phydev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
|
||||
phydev->supported);
|
||||
|
||||
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
|
||||
phydev->advertising);
|
||||
linkmode_copy(cmd->link_modes.supported, phydev->supported);
|
||||
linkmode_copy(cmd->link_modes.advertising, phydev->advertising);
|
||||
|
||||
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
|
||||
phydev->lp_advertising);
|
||||
@@ -442,7 +439,8 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
|
||||
}
|
||||
break;
|
||||
case MII_ADVERTISE:
|
||||
phydev->advertising = mii_adv_to_ethtool_adv_t(val);
|
||||
mii_adv_to_linkmode_adv_t(phydev->advertising,
|
||||
val);
|
||||
change_autoneg = true;
|
||||
break;
|
||||
default:
|
||||
@@ -604,20 +602,38 @@ static int phy_poll_aneg_done(struct phy_device *phydev)
|
||||
*/
|
||||
int phy_speed_down(struct phy_device *phydev, bool sync)
|
||||
{
|
||||
u32 adv = phydev->lp_advertising & phydev->supported;
|
||||
u32 adv_old = phydev->advertising;
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv);
|
||||
int ret;
|
||||
|
||||
if (phydev->autoneg != AUTONEG_ENABLE)
|
||||
return 0;
|
||||
|
||||
if (adv & PHY_10BT_FEATURES)
|
||||
phydev->advertising &= ~(PHY_100BT_FEATURES |
|
||||
PHY_1000BT_FEATURES);
|
||||
else if (adv & PHY_100BT_FEATURES)
|
||||
phydev->advertising &= ~PHY_1000BT_FEATURES;
|
||||
linkmode_copy(adv_old, phydev->advertising);
|
||||
ethtool_convert_legacy_u32_to_link_mode(adv, phydev->lp_advertising);
|
||||
linkmode_and(adv, adv, phydev->supported);
|
||||
|
||||
if (phydev->advertising == adv_old)
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, adv) ||
|
||||
linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, adv)) {
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
||||
phydev->advertising);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
phydev->advertising);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
phydev->advertising);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
phydev->advertising);
|
||||
} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
||||
adv) ||
|
||||
linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
adv)) {
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
phydev->advertising);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
phydev->advertising);
|
||||
}
|
||||
|
||||
if (linkmode_equal(phydev->advertising, adv_old))
|
||||
return 0;
|
||||
|
||||
ret = phy_config_aneg(phydev);
|
||||
@@ -636,15 +652,30 @@ EXPORT_SYMBOL_GPL(phy_speed_down);
|
||||
*/
|
||||
int phy_speed_up(struct phy_device *phydev)
|
||||
{
|
||||
u32 mask = PHY_10BT_FEATURES | PHY_100BT_FEATURES | PHY_1000BT_FEATURES;
|
||||
u32 adv_old = phydev->advertising;
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(all_speeds) = { 0, };
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(not_speeds);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(speeds);
|
||||
|
||||
linkmode_copy(adv_old, phydev->advertising);
|
||||
|
||||
if (phydev->autoneg != AUTONEG_ENABLE)
|
||||
return 0;
|
||||
|
||||
phydev->advertising = (adv_old & ~mask) | (phydev->supported & mask);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, all_speeds);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, all_speeds);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, all_speeds);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, all_speeds);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, all_speeds);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, all_speeds);
|
||||
|
||||
if (phydev->advertising == adv_old)
|
||||
linkmode_andnot(not_speeds, adv_old, all_speeds);
|
||||
linkmode_copy(supported, phydev->supported);
|
||||
linkmode_and(speeds, supported, all_speeds);
|
||||
linkmode_or(phydev->advertising, not_speeds, speeds);
|
||||
|
||||
if (linkmode_equal(phydev->advertising, adv_old))
|
||||
return 0;
|
||||
|
||||
return phy_config_aneg(phydev);
|
||||
@@ -973,6 +1004,30 @@ void phy_mac_interrupt(struct phy_device *phydev)
|
||||
}
|
||||
EXPORT_SYMBOL(phy_mac_interrupt);
|
||||
|
||||
static void mmd_eee_adv_to_linkmode(unsigned long *advertising, u16 eee_adv)
|
||||
{
|
||||
linkmode_zero(advertising);
|
||||
|
||||
if (eee_adv & MDIO_EEE_100TX)
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
advertising);
|
||||
if (eee_adv & MDIO_EEE_1000T)
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
advertising);
|
||||
if (eee_adv & MDIO_EEE_10GT)
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
|
||||
advertising);
|
||||
if (eee_adv & MDIO_EEE_1000KX)
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
|
||||
advertising);
|
||||
if (eee_adv & MDIO_EEE_10GKX4)
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
|
||||
advertising);
|
||||
if (eee_adv & MDIO_EEE_10GKR)
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
|
||||
advertising);
|
||||
}
|
||||
|
||||
/**
|
||||
* phy_init_eee - init and check the EEE feature
|
||||
* @phydev: target phy_device struct
|
||||
@@ -991,9 +1046,12 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
|
||||
/* According to 802.3az,the EEE is supported only in full duplex-mode.
|
||||
*/
|
||||
if (phydev->duplex == DUPLEX_FULL) {
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(common);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(lp);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv);
|
||||
int eee_lp, eee_cap, eee_adv;
|
||||
u32 lp, cap, adv;
|
||||
int status;
|
||||
u32 cap;
|
||||
|
||||
/* Read phy status to properly get the right settings */
|
||||
status = phy_read_status(phydev);
|
||||
@@ -1020,9 +1078,11 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
|
||||
if (eee_adv <= 0)
|
||||
goto eee_exit_err;
|
||||
|
||||
adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv);
|
||||
lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp);
|
||||
if (!phy_check_valid(phydev->speed, phydev->duplex, lp & adv))
|
||||
mmd_eee_adv_to_linkmode(adv, eee_adv);
|
||||
mmd_eee_adv_to_linkmode(lp, eee_lp);
|
||||
linkmode_and(common, adv, lp);
|
||||
|
||||
if (!phy_check_valid(phydev->speed, phydev->duplex, common))
|
||||
goto eee_exit_err;
|
||||
|
||||
if (clk_stop_enable) {
|
||||
|
@@ -66,10 +66,12 @@ static const int phy_basic_ports_array[] = {
|
||||
ETHTOOL_LINK_MODE_TP_BIT,
|
||||
ETHTOOL_LINK_MODE_MII_BIT,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(phy_basic_ports_array);
|
||||
|
||||
static const int phy_fibre_port_array[] = {
|
||||
ETHTOOL_LINK_MODE_FIBRE_BIT,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(phy_fibre_port_array);
|
||||
|
||||
static const int phy_all_ports_features_array[] = {
|
||||
ETHTOOL_LINK_MODE_Autoneg_BIT,
|
||||
@@ -80,27 +82,32 @@ static const int phy_all_ports_features_array[] = {
|
||||
ETHTOOL_LINK_MODE_BNC_BIT,
|
||||
ETHTOOL_LINK_MODE_Backplane_BIT,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(phy_all_ports_features_array);
|
||||
|
||||
static const int phy_10_100_features_array[] = {
|
||||
const int phy_10_100_features_array[4] = {
|
||||
ETHTOOL_LINK_MODE_10baseT_Half_BIT,
|
||||
ETHTOOL_LINK_MODE_10baseT_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
||||
ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(phy_10_100_features_array);
|
||||
|
||||
static const int phy_basic_t1_features_array[] = {
|
||||
const int phy_basic_t1_features_array[2] = {
|
||||
ETHTOOL_LINK_MODE_TP_BIT,
|
||||
ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(phy_basic_t1_features_array);
|
||||
|
||||
static const int phy_gbit_features_array[] = {
|
||||
const int phy_gbit_features_array[2] = {
|
||||
ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(phy_gbit_features_array);
|
||||
|
||||
static const int phy_10gbit_features_array[] = {
|
||||
const int phy_10gbit_features_array[1] = {
|
||||
ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(phy_10gbit_features_array);
|
||||
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) __ro_after_init;
|
||||
EXPORT_SYMBOL_GPL(phy_10gbit_full_features);
|
||||
@@ -1441,8 +1448,13 @@ static int genphy_config_advert(struct phy_device *phydev)
|
||||
int err, changed = 0;
|
||||
|
||||
/* Only allow advertising what this PHY supports */
|
||||
phydev->advertising &= phydev->supported;
|
||||
advertise = phydev->advertising;
|
||||
linkmode_and(phydev->advertising, phydev->advertising,
|
||||
phydev->supported);
|
||||
if (!ethtool_convert_link_mode_to_legacy_u32(&advertise,
|
||||
phydev->advertising))
|
||||
phydev_warn(phydev, "PHY advertising (%*pb) more modes than genphy supports, some modes not advertised.\n",
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS,
|
||||
phydev->advertising);
|
||||
|
||||
/* Setup standard advertisement */
|
||||
adv = phy_read(phydev, MII_ADVERTISE);
|
||||
@@ -1481,10 +1493,11 @@ static int genphy_config_advert(struct phy_device *phydev)
|
||||
oldadv = adv;
|
||||
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
||||
|
||||
if (phydev->supported & (SUPPORTED_1000baseT_Half |
|
||||
SUPPORTED_1000baseT_Full)) {
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
phydev->supported) ||
|
||||
linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
phydev->supported))
|
||||
adv |= ethtool_adv_to_mii_ctrl1000_t(advertise);
|
||||
}
|
||||
|
||||
if (adv != oldadv)
|
||||
changed = 1;
|
||||
@@ -1692,8 +1705,10 @@ int genphy_read_status(struct phy_device *phydev)
|
||||
phydev->lp_advertising = 0;
|
||||
|
||||
if (AUTONEG_ENABLE == phydev->autoneg) {
|
||||
if (phydev->supported & (SUPPORTED_1000baseT_Half
|
||||
| SUPPORTED_1000baseT_Full)) {
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
phydev->supported) ||
|
||||
linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
phydev->supported)) {
|
||||
lpagb = phy_read(phydev, MII_STAT1000);
|
||||
if (lpagb < 0)
|
||||
return lpagb;
|
||||
@@ -1800,11 +1815,13 @@ EXPORT_SYMBOL(genphy_soft_reset);
|
||||
int genphy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
int val;
|
||||
u32 features;
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(features) = { 0, };
|
||||
|
||||
features = (SUPPORTED_TP | SUPPORTED_MII
|
||||
| SUPPORTED_AUI | SUPPORTED_FIBRE |
|
||||
SUPPORTED_BNC | SUPPORTED_Pause | SUPPORTED_Asym_Pause);
|
||||
linkmode_set_bit_array(phy_basic_ports_array,
|
||||
ARRAY_SIZE(phy_basic_ports_array),
|
||||
features);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, features);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, features);
|
||||
|
||||
/* Do we support autonegotiation? */
|
||||
val = phy_read(phydev, MII_BMSR);
|
||||
@@ -1812,16 +1829,16 @@ int genphy_config_init(struct phy_device *phydev)
|
||||
return val;
|
||||
|
||||
if (val & BMSR_ANEGCAPABLE)
|
||||
features |= SUPPORTED_Autoneg;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, features);
|
||||
|
||||
if (val & BMSR_100FULL)
|
||||
features |= SUPPORTED_100baseT_Full;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, features);
|
||||
if (val & BMSR_100HALF)
|
||||
features |= SUPPORTED_100baseT_Half;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, features);
|
||||
if (val & BMSR_10FULL)
|
||||
features |= SUPPORTED_10baseT_Full;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, features);
|
||||
if (val & BMSR_10HALF)
|
||||
features |= SUPPORTED_10baseT_Half;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, features);
|
||||
|
||||
if (val & BMSR_ESTATEN) {
|
||||
val = phy_read(phydev, MII_ESTATUS);
|
||||
@@ -1829,13 +1846,15 @@ int genphy_config_init(struct phy_device *phydev)
|
||||
return val;
|
||||
|
||||
if (val & ESTATUS_1000_TFULL)
|
||||
features |= SUPPORTED_1000baseT_Full;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
features);
|
||||
if (val & ESTATUS_1000_THALF)
|
||||
features |= SUPPORTED_1000baseT_Half;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
features);
|
||||
}
|
||||
|
||||
phydev->supported &= features;
|
||||
phydev->advertising &= features;
|
||||
linkmode_and(phydev->supported, phydev->supported, features);
|
||||
linkmode_and(phydev->advertising, phydev->advertising, features);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1879,20 +1898,37 @@ EXPORT_SYMBOL(genphy_loopback);
|
||||
|
||||
static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
|
||||
{
|
||||
phydev->supported &= ~(PHY_1000BT_FEATURES | PHY_100BT_FEATURES |
|
||||
PHY_10BT_FEATURES);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(speeds) = { 0, };
|
||||
|
||||
linkmode_set_bit_array(phy_10_100_features_array,
|
||||
ARRAY_SIZE(phy_10_100_features_array),
|
||||
speeds);
|
||||
linkmode_set_bit_array(phy_gbit_features_array,
|
||||
ARRAY_SIZE(phy_gbit_features_array),
|
||||
speeds);
|
||||
|
||||
linkmode_andnot(phydev->supported, phydev->supported, speeds);
|
||||
|
||||
switch (max_speed) {
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
case SPEED_1000:
|
||||
phydev->supported |= PHY_1000BT_FEATURES;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
/* fall through */
|
||||
case SPEED_100:
|
||||
phydev->supported |= PHY_100BT_FEATURES;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
/* fall through */
|
||||
case SPEED_10:
|
||||
phydev->supported |= PHY_10BT_FEATURES;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1906,7 +1942,7 @@ int phy_set_max_speed(struct phy_device *phydev, u32 max_speed)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
phydev->advertising = phydev->supported;
|
||||
linkmode_copy(phydev->advertising, phydev->supported);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1923,10 +1959,8 @@ EXPORT_SYMBOL(phy_set_max_speed);
|
||||
*/
|
||||
void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode)
|
||||
{
|
||||
WARN_ON(link_mode > 31);
|
||||
|
||||
phydev->supported &= ~BIT(link_mode);
|
||||
phydev->advertising = phydev->supported;
|
||||
linkmode_clear_bit(link_mode, phydev->supported);
|
||||
linkmode_copy(phydev->advertising, phydev->supported);
|
||||
}
|
||||
EXPORT_SYMBOL(phy_remove_link_mode);
|
||||
|
||||
@@ -1939,9 +1973,9 @@ EXPORT_SYMBOL(phy_remove_link_mode);
|
||||
*/
|
||||
void phy_support_sym_pause(struct phy_device *phydev)
|
||||
{
|
||||
phydev->supported &= ~SUPPORTED_Asym_Pause;
|
||||
phydev->supported |= SUPPORTED_Pause;
|
||||
phydev->advertising = phydev->supported;
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);
|
||||
linkmode_copy(phydev->advertising, phydev->supported);
|
||||
}
|
||||
EXPORT_SYMBOL(phy_support_sym_pause);
|
||||
|
||||
@@ -1953,8 +1987,9 @@ EXPORT_SYMBOL(phy_support_sym_pause);
|
||||
*/
|
||||
void phy_support_asym_pause(struct phy_device *phydev)
|
||||
{
|
||||
phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
phydev->advertising = phydev->supported;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported);
|
||||
linkmode_copy(phydev->advertising, phydev->supported);
|
||||
}
|
||||
EXPORT_SYMBOL(phy_support_asym_pause);
|
||||
|
||||
@@ -1972,12 +2007,13 @@ EXPORT_SYMBOL(phy_support_asym_pause);
|
||||
void phy_set_sym_pause(struct phy_device *phydev, bool rx, bool tx,
|
||||
bool autoneg)
|
||||
{
|
||||
phydev->supported &= ~SUPPORTED_Pause;
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);
|
||||
|
||||
if (rx && tx && autoneg)
|
||||
phydev->supported |= SUPPORTED_Pause;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->supported);
|
||||
|
||||
phydev->advertising = phydev->supported;
|
||||
linkmode_copy(phydev->advertising, phydev->supported);
|
||||
}
|
||||
EXPORT_SYMBOL(phy_set_sym_pause);
|
||||
|
||||
@@ -1994,20 +2030,29 @@ EXPORT_SYMBOL(phy_set_sym_pause);
|
||||
*/
|
||||
void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx)
|
||||
{
|
||||
u16 oldadv = phydev->advertising;
|
||||
u16 newadv = oldadv &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(oldadv);
|
||||
|
||||
if (rx)
|
||||
newadv |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
if (tx)
|
||||
newadv ^= SUPPORTED_Asym_Pause;
|
||||
linkmode_copy(oldadv, phydev->advertising);
|
||||
|
||||
if (oldadv != newadv) {
|
||||
phydev->advertising = newadv;
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->advertising);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->advertising);
|
||||
|
||||
if (phydev->autoneg)
|
||||
phy_start_aneg(phydev);
|
||||
if (rx) {
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->advertising);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->advertising);
|
||||
}
|
||||
|
||||
if (tx)
|
||||
linkmode_change_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->advertising);
|
||||
|
||||
if (!linkmode_equal(oldadv, phydev->advertising) &&
|
||||
phydev->autoneg)
|
||||
phy_start_aneg(phydev);
|
||||
}
|
||||
EXPORT_SYMBOL(phy_set_asym_pause);
|
||||
|
||||
@@ -2023,8 +2068,10 @@ EXPORT_SYMBOL(phy_set_asym_pause);
|
||||
bool phy_validate_pause(struct phy_device *phydev,
|
||||
struct ethtool_pauseparam *pp)
|
||||
{
|
||||
if (!(phydev->supported & SUPPORTED_Pause) ||
|
||||
(!(phydev->supported & SUPPORTED_Asym_Pause) &&
|
||||
if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->supported) ||
|
||||
(!linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->supported) &&
|
||||
pp->rx_pause != pp->tx_pause))
|
||||
return false;
|
||||
return true;
|
||||
@@ -2112,9 +2159,9 @@ static int phy_probe(struct device *dev)
|
||||
* or both of these values
|
||||
*/
|
||||
ethtool_convert_link_mode_to_legacy_u32(&features, phydrv->features);
|
||||
phydev->supported = features;
|
||||
linkmode_copy(phydev->supported, phydrv->features);
|
||||
of_set_phy_supported(phydev);
|
||||
phydev->advertising = phydev->supported;
|
||||
linkmode_copy(phydev->advertising, phydev->supported);
|
||||
|
||||
/* Get the EEE modes we want to prohibit. We will ask
|
||||
* the PHY stop advertising these mode later on
|
||||
@@ -2134,14 +2181,22 @@ static int phy_probe(struct device *dev)
|
||||
*/
|
||||
if (test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydrv->features) ||
|
||||
test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydrv->features)) {
|
||||
phydev->supported &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->supported);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->supported);
|
||||
if (test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydrv->features))
|
||||
phydev->supported |= SUPPORTED_Pause;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->supported);
|
||||
if (test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydrv->features))
|
||||
phydev->supported |= SUPPORTED_Asym_Pause;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->supported);
|
||||
} else {
|
||||
phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->supported);
|
||||
}
|
||||
|
||||
/* Set the state to READY by default */
|
||||
|
@@ -191,8 +191,7 @@ static int phylink_parse_fixedlink(struct phylink *pl,
|
||||
phylink_validate(pl, pl->supported, &pl->link_config);
|
||||
|
||||
s = phy_lookup_setting(pl->link_config.speed, pl->link_config.duplex,
|
||||
pl->supported,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS, true);
|
||||
pl->supported, true);
|
||||
linkmode_zero(pl->supported);
|
||||
phylink_set(pl->supported, MII);
|
||||
if (s) {
|
||||
@@ -634,13 +633,11 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy)
|
||||
{
|
||||
struct phylink_link_state config;
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
|
||||
u32 advertising;
|
||||
int ret;
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ethtool_convert_legacy_u32_to_link_mode(supported, phy->supported);
|
||||
ethtool_convert_legacy_u32_to_link_mode(config.advertising,
|
||||
phy->advertising);
|
||||
linkmode_copy(supported, phy->supported);
|
||||
linkmode_copy(config.advertising, phy->advertising);
|
||||
config.interface = pl->link_config.interface;
|
||||
|
||||
/*
|
||||
@@ -673,15 +670,14 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy)
|
||||
linkmode_copy(pl->link_config.advertising, config.advertising);
|
||||
|
||||
/* Restrict the phy advertisement according to the MAC support. */
|
||||
ethtool_convert_link_mode_to_legacy_u32(&advertising, config.advertising);
|
||||
phy->advertising = advertising;
|
||||
linkmode_copy(phy->advertising, config.advertising);
|
||||
mutex_unlock(&pl->state_mutex);
|
||||
mutex_unlock(&phy->lock);
|
||||
|
||||
netdev_dbg(pl->netdev,
|
||||
"phy: setting supported %*pb advertising 0x%08x\n",
|
||||
"phy: setting supported %*pb advertising %*pb\n",
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS, pl->supported,
|
||||
phy->advertising);
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS, phy->advertising);
|
||||
|
||||
phy_start_machine(phy);
|
||||
if (phy->irq > 0)
|
||||
@@ -1088,8 +1084,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
|
||||
* duplex.
|
||||
*/
|
||||
s = phy_lookup_setting(kset->base.speed, kset->base.duplex,
|
||||
pl->supported,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS, false);
|
||||
pl->supported, false);
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
|
Referência em uma nova issue
Block a user