diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index ffce528aa00e4a3a030af4dc283b8e04fa18237d..57c5f48d19a47f31d26341ae4dbd95290b50110d 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -513,29 +513,47 @@ static void macb_validate(struct phylink_config *config, struct net_device *ndev = to_net_dev(config->dev); __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; struct macb *bp = netdev_priv(ndev); + bool have_1g, have_sgmii, have_10g; + + /* Determine what modes are supported */ + if (macb_is_gem(bp) && + (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)) { + have_1g = true; + if (bp->caps & MACB_CAPS_PCS) + have_sgmii = true; + if (bp->caps & MACB_CAPS_HIGH_SPEED) + have_10g = true; + } + + /* Eliminate unsupported modes */ + switch (state->interface) { + case PHY_INTERFACE_MODE_NA: + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_RMII: + break; - /* We only support MII, RMII, GMII, RGMII & SGMII. */ - if (state->interface != PHY_INTERFACE_MODE_NA && - state->interface != PHY_INTERFACE_MODE_MII && - state->interface != PHY_INTERFACE_MODE_RMII && - state->interface != PHY_INTERFACE_MODE_GMII && - state->interface != PHY_INTERFACE_MODE_SGMII && - state->interface != PHY_INTERFACE_MODE_10GBASER && - !phy_interface_mode_is_rgmii(state->interface)) { + case PHY_INTERFACE_MODE_GMII: + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + if (have_1g) + break; linkmode_zero(supported); return; - } - if (!macb_is_gem(bp) && - (state->interface == PHY_INTERFACE_MODE_GMII || - phy_interface_mode_is_rgmii(state->interface))) { + case PHY_INTERFACE_MODE_SGMII: + if (have_sgmii) + break; linkmode_zero(supported); return; - } - if (state->interface == PHY_INTERFACE_MODE_10GBASER && - !(bp->caps & MACB_CAPS_HIGH_SPEED && - bp->caps & MACB_CAPS_PCS)) { + case PHY_INTERFACE_MODE_10GBASER: + if (have_10g) + break; + fallthrough; + + default: linkmode_zero(supported); return; } @@ -544,32 +562,48 @@ static void macb_validate(struct phylink_config *config, phylink_set(mask, Autoneg); phylink_set(mask, Asym_Pause); - if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE && - (state->interface == PHY_INTERFACE_MODE_NA || - state->interface == PHY_INTERFACE_MODE_10GBASER)) { - phylink_set_10g_modes(mask); - phylink_set(mask, 10000baseKR_Full); + /* And set the appropriate mask */ + switch (state->interface) { + case PHY_INTERFACE_MODE_NA: + case PHY_INTERFACE_MODE_10GBASER: + if (have_10g) { + phylink_set_10g_modes(mask); + phylink_set(mask, 10000baseKR_Full); + } if (state->interface != PHY_INTERFACE_MODE_NA) - goto out; - } + break; + fallthrough; + + /* FIXME: Do we actually support 10/100 for SGMII? Half duplex? */ + case PHY_INTERFACE_MODE_SGMII: + if (!have_sgmii && state->interface != PHY_INTERFACE_MODE_NA) + break; + fallthrough; + + case PHY_INTERFACE_MODE_GMII: + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + if (have_1g) { + phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 1000baseX_Full); + + if (!(bp->caps & MACB_CAPS_NO_GIGABIT_HALF)) + phylink_set(mask, 1000baseT_Half); + } else if (state->interface != PHY_INTERFACE_MODE_NA) { + break; + } + fallthrough; - phylink_set(mask, 10baseT_Half); - phylink_set(mask, 10baseT_Full); - phylink_set(mask, 100baseT_Half); - phylink_set(mask, 100baseT_Full); - - if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE && - (state->interface == PHY_INTERFACE_MODE_NA || - state->interface == PHY_INTERFACE_MODE_GMII || - state->interface == PHY_INTERFACE_MODE_SGMII || - phy_interface_mode_is_rgmii(state->interface))) { - phylink_set(mask, 1000baseT_Full); - phylink_set(mask, 1000baseX_Full); - - if (!(bp->caps & MACB_CAPS_NO_GIGABIT_HALF)) - phylink_set(mask, 1000baseT_Half); + default: + phylink_set(mask, 10baseT_Half); + phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + break; } -out: + linkmode_and(supported, supported, mask); linkmode_and(state->advertising, state->advertising, mask); }