summaryrefslogtreecommitdiff
path: root/drivers/net/phy/phylink.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/phylink.c')
-rw-r--r--drivers/net/phy/phylink.c67
1 files changed, 54 insertions, 13 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 39d85e47422e..48d3bd3e9fc7 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -121,6 +121,19 @@ do { \
})
#endif
+static const phy_interface_t phylink_sfp_interface_preference[] = {
+ PHY_INTERFACE_MODE_25GBASER,
+ PHY_INTERFACE_MODE_USXGMII,
+ PHY_INTERFACE_MODE_10GBASER,
+ PHY_INTERFACE_MODE_5GBASER,
+ PHY_INTERFACE_MODE_2500BASEX,
+ PHY_INTERFACE_MODE_SGMII,
+ PHY_INTERFACE_MODE_1000BASEX,
+ PHY_INTERFACE_MODE_100BASEX,
+};
+
+static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
+
/**
* phylink_set_port_modes() - set the port type modes in the ethtool mask
* @mask: ethtool link mode mask
@@ -1764,6 +1777,47 @@ 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 the PHY provides a bitmap of the interfaces it will be using
+ * depending on the negotiated media speeds, use this to validate
+ * which ethtool link modes can be used.
+ */
+ if (!phy_interface_empty(phy->possible_interfaces)) {
+ /* We only care about the union of the PHY's interfaces and
+ * those which the host supports.
+ */
+ phy_interface_and(interfaces, phy->possible_interfaces,
+ pl->config->supported_interfaces);
+
+ if (phy_interface_empty(interfaces)) {
+ phylink_err(pl, "PHY has no common interfaces\n");
+ return -EINVAL;
+ }
+
+ if (phy_on_sfp(phy)) {
+ /* If the PHY is on a SFP, limit the interfaces to
+ * those that can be used with a SFP module.
+ */
+ phy_interface_and(interfaces, interfaces,
+ phylink_sfp_interfaces);
+
+ if (phy_interface_empty(interfaces)) {
+ phylink_err(pl, "SFP PHY's possible interfaces becomes empty\n");
+ return -EINVAL;
+ }
+ }
+
+ phylink_dbg(pl, "PHY %s uses interfaces %*pbl, validating %*pbl\n",
+ phydev_name(phy),
+ (int)PHY_INTERFACE_MODE_MAX,
+ phy->possible_interfaces,
+ (int)PHY_INTERFACE_MODE_MAX, interfaces);
+
+ return phylink_validate_mask(pl, phy, supported, state,
+ interfaces);
+ }
+
/* Check whether we would use rate matching for the proposed interface
* mode.
*/
@@ -3032,19 +3086,6 @@ static void phylink_sfp_detach(void *upstream, struct sfp_bus *bus)
pl->netdev->sfp_bus = NULL;
}
-static const phy_interface_t phylink_sfp_interface_preference[] = {
- PHY_INTERFACE_MODE_25GBASER,
- PHY_INTERFACE_MODE_USXGMII,
- PHY_INTERFACE_MODE_10GBASER,
- PHY_INTERFACE_MODE_5GBASER,
- PHY_INTERFACE_MODE_2500BASEX,
- PHY_INTERFACE_MODE_SGMII,
- PHY_INTERFACE_MODE_1000BASEX,
- PHY_INTERFACE_MODE_100BASEX,
-};
-
-static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
-
static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl,
const unsigned long *intf)
{