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>
This commit is contained in:
David S. Miller 2020-09-19 16:54:35 -07:00
commit dd92f17989
6 changed files with 92 additions and 4 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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 ),

View File

@ -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
};

View File

@ -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);

View File

@ -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