diff options
author | David S. Miller <davem@davemloft.net> | 2020-09-19 16:54:35 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-09-19 16:54:43 -0700 |
commit | dd92f1798981a9d7241d788dd478aea3460b09a1 (patch) | |
tree | d0fe4ba12a193cd92fa1eadfefe51b9a5191aa34 | |
parent | 09599729ee1ae9c418c0bd0fd48efff8a98d1c4d (diff) | |
parent | 9ef7e18ba52b4970934bed24589cff0c8be50c83 (diff) |
Merge branch '100base-Fx-link-modes'
Dan Murphy says:
====================
100base Fx link modes
As per patch https://lore.kernel.org/patchwork/patch/1300241/ the link
modes for 100base FX full and half duplex modes did not exist. Adding
these link modes to the core and ethtool allow devices like the
DP83822, DP83869 and Broadcomm PHYs to properly advertise the correct
mode for Fiber 100Mbps.
Corresponding user land ethtool patches are available but rely on
these patches to be applied first.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/phy/dp83822.c | 13 | ||||
-rw-r--r-- | drivers/net/phy/dp83869.c | 73 | ||||
-rw-r--r-- | drivers/net/phy/phy-core.c | 4 | ||||
-rw-r--r-- | include/uapi/linux/ethtool.h | 2 | ||||
-rw-r--r-- | net/ethtool/common.c | 2 | ||||
-rw-r--r-- | net/ethtool/linkmodes.c | 2 |
6 files changed, 92 insertions, 4 deletions
diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index 732c8bec7452..c162c9551bd1 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -110,9 +110,8 @@ #define DP83822_RX_ER_SHIFT 8 #define MII_DP83822_FIBER_ADVERTISE (ADVERTISED_TP | ADVERTISED_MII | \ - ADVERTISED_FIBRE | ADVERTISED_BNC | \ - ADVERTISED_Pause | ADVERTISED_Asym_Pause | \ - ADVERTISED_100baseT_Full) + ADVERTISED_FIBRE | \ + ADVERTISED_Pause | ADVERTISED_Asym_Pause) struct dp83822_private { bool fx_signal_det_low; @@ -406,6 +405,14 @@ static int dp83822_config_init(struct phy_device *phydev) phydev->supported); linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, + phydev->advertising); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, + phydev->advertising); /* Auto neg is not supported in fiber mode */ bmcr = phy_read(phydev, MII_BMCR); diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index 6b98d74b5102..81899bc99add 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -52,6 +52,10 @@ BMCR_FULLDPLX | \ BMCR_SPEED1000) +#define MII_DP83869_FIBER_ADVERTISE (ADVERTISED_FIBRE | \ + ADVERTISED_Pause | \ + ADVERTISED_Asym_Pause) + /* This is the same bit mask as the BMCR so re-use the BMCR default */ #define DP83869_FX_CTRL_DEFAULT MII_DP83869_BMCR_DEFAULT @@ -118,6 +122,28 @@ struct dp83869_private { int mode; }; +static int dp83869_read_status(struct phy_device *phydev) +{ + struct dp83869_private *dp83869 = phydev->priv; + int ret; + + ret = genphy_read_status(phydev); + if (ret) + return ret; + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) { + if (phydev->link) { + if (dp83869->mode == DP83869_RGMII_100_BASE) + phydev->speed = SPEED_100; + } else { + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + } + } + + return 0; +} + static int dp83869_ack_interrupt(struct phy_device *phydev) { int err = phy_read(phydev, MII_DP83869_ISR); @@ -295,6 +321,51 @@ static int dp83869_configure_rgmii(struct phy_device *phydev, return ret; } +static int dp83869_configure_fiber(struct phy_device *phydev, + struct dp83869_private *dp83869) +{ + int bmcr; + int ret; + + /* Only allow advertising what this PHY supports */ + linkmode_and(phydev->advertising, phydev->advertising, + phydev->supported); + + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); + linkmode_set_bit(ADVERTISED_FIBRE, phydev->advertising); + + if (dp83869->mode == DP83869_RGMII_1000_BASE) { + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + phydev->supported); + } else { + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, + phydev->supported); + + /* Auto neg is not supported in 100base FX mode */ + bmcr = phy_read(phydev, MII_BMCR); + if (bmcr < 0) + return bmcr; + + phydev->autoneg = AUTONEG_DISABLE; + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->advertising); + + if (bmcr & BMCR_ANENABLE) { + ret = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0); + if (ret < 0) + return ret; + } + } + + /* Update advertising from supported */ + linkmode_or(phydev->advertising, phydev->advertising, + phydev->supported); + + return 0; +} + static int dp83869_configure_mode(struct phy_device *phydev, struct dp83869_private *dp83869) { @@ -384,6 +455,7 @@ static int dp83869_configure_mode(struct phy_device *phydev, break; case DP83869_RGMII_1000_BASE: case DP83869_RGMII_100_BASE: + ret = dp83869_configure_fiber(phydev, dp83869); break; default: return -EINVAL; @@ -494,6 +566,7 @@ static struct phy_driver dp83869_driver[] = { /* IRQ related */ .ack_interrupt = dp83869_ack_interrupt, .config_intr = dp83869_config_intr, + .read_status = dp83869_read_status, .suspend = genphy_suspend, .resume = genphy_resume, diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index ff8e14b01eeb..de5b869139d7 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -8,7 +8,7 @@ const char *phy_speed_to_str(int speed) { - BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 90, + BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 92, "Enum ethtool_link_mode_bit_indices and phylib are out of sync. " "If a speed or mode has been added please update phy_speed_to_str " "and the PHY settings array.\n"); @@ -160,6 +160,8 @@ static const struct phy_setting settings[] = { PHY_SETTING( 100, FULL, 100baseT_Full ), PHY_SETTING( 100, FULL, 100baseT1_Full ), PHY_SETTING( 100, HALF, 100baseT_Half ), + PHY_SETTING( 100, HALF, 100baseFX_Half ), + PHY_SETTING( 100, FULL, 100baseFX_Full ), /* 10M */ PHY_SETTING( 10, FULL, 10baseT_Full ), PHY_SETTING( 10, HALF, 10baseT_Half ), diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index b4f2d134e713..9ca87bc73c44 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -1617,6 +1617,8 @@ enum ethtool_link_mode_bit_indices { ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT = 87, ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT = 88, ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT = 89, + ETHTOOL_LINK_MODE_100baseFX_Half_BIT = 90, + ETHTOOL_LINK_MODE_100baseFX_Full_BIT = 91, /* must be last entry */ __ETHTOOL_LINK_MODE_MASK_NBITS }; diff --git a/net/ethtool/common.c b/net/ethtool/common.c index ed19573fccd7..24036e3055a1 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -192,6 +192,8 @@ const char link_mode_names[][ETH_GSTRING_LEN] = { __DEFINE_LINK_MODE_NAME(400000, LR4_ER4_FR4, Full), __DEFINE_LINK_MODE_NAME(400000, DR4, Full), __DEFINE_LINK_MODE_NAME(400000, CR4, Full), + __DEFINE_LINK_MODE_NAME(100, FX, Half), + __DEFINE_LINK_MODE_NAME(100, FX, Full), }; static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS); diff --git a/net/ethtool/linkmodes.c b/net/ethtool/linkmodes.c index 7044a2853886..29dcd675b65a 100644 --- a/net/ethtool/linkmodes.c +++ b/net/ethtool/linkmodes.c @@ -272,6 +272,8 @@ static const struct link_mode_info link_mode_params[] = { __DEFINE_LINK_MODE_PARAMS(400000, LR4_ER4_FR4, Full), __DEFINE_LINK_MODE_PARAMS(400000, DR4, Full), __DEFINE_LINK_MODE_PARAMS(400000, CR4, Full), + __DEFINE_LINK_MODE_PARAMS(100, FX, Half), + __DEFINE_LINK_MODE_PARAMS(100, FX, Full), }; static const struct nla_policy |