diff options
-rw-r--r-- | drivers/net/phy/phylink.c | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index c425ddf2d52e..09b9569a7d8f 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1423,18 +1423,39 @@ static int phylink_validate_phy(struct phylink *pl, struct phy_device *phy, unsigned long *supported, struct phylink_link_state *state) { + DECLARE_PHY_INTERFACE_MASK(interfaces); + + /* If this is a clause 22 PHY, it only operates in a single mode. */ + if (!phy->is_c45) + return phylink_validate(pl, supported, state); + /* Clause 45 PHYs switch their Serdes lane between several different - * modes, normally 10GBASE-R, SGMII. Some use 2500BASE-X for 2.5G - * speeds. We really need to know which interface modes the PHY and - * MAC supports to properly work out which linkmodes can be supported. + * modes according to the negotiated media speed. For example, the + * interface may switch between 10GBASE-R, 5GBASE-R, 2500BASE-X and + * SGMII. + */ + + /* Backwards compatibility for those MAC drivers that don't set + * their supported_interfaces, or PHY drivers that don't set + * their possible_interfaces. */ - if (phy->is_c45 && + if ((phy_interface_empty(pl->config->supported_interfaces) || + phy_interface_empty(phy->possible_interfaces)) && state->interface != PHY_INTERFACE_MODE_RXAUI && state->interface != PHY_INTERFACE_MODE_XAUI && - state->interface != PHY_INTERFACE_MODE_USXGMII) + state->interface != PHY_INTERFACE_MODE_USXGMII) { state->interface = PHY_INTERFACE_MODE_NA; + return phylink_validate(pl, supported, state); + } + + /* Calculate the union of the interfaces the PHY supports in + * its configured state, and the host's supported interfaces. + * We never want an interface that isn't supported by the host. + */ + phy_interface_and(interfaces, phy->possible_interfaces, + pl->config->supported_interfaces); - return phylink_validate(pl, supported, state); + return phylink_validate_mask(pl, supported, state, interfaces); } static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, |