From 4b36015671ffabc3a8ff61c4f45e41f456707be1 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 26 Nov 2021 17:31:05 +0000 Subject: net: phylink: validate only used interfaces for c45 PHYs Some clause 45 PHYs such as Marvell 88X33x0 and Broadcom 84881 switch between a set of interface types depending on the negotiated media speed. We currently validate this kind of PHY using all MAC capabilities, which is not correct if that would give a superset of the ethtool link modes. This commit uses the previously introduced phy possible_interfaces, and the recently introduced supported_interfaces to calculate the union of interface support, and then validates only those interfaces. Signed-off-by: Russell King (Oracle) --- drivers/net/phy/phylink.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 62925e096fbe..1a4305a07285 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1452,18 +1452,38 @@ 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(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, -- cgit