summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2020-03-03 12:12:43 +0000
committerRussell King (Oracle) <rmk+kernel@armlinux.org.uk>2021-09-19 13:22:15 +0100
commitb1f7bec7a2c8b3bd05258fd2f8fd739d36f758d2 (patch)
treee37dd6e7addfb759af73d87d7f2915c64ae037f0
parent03a6c744372a8682f913dff44a874c2c2d01cfd6 (diff)
net: phylink: use phy interface mode bitmaps for optical modules
Where a MAC provides the PHY interface mode capabilities, use the PHY interface mode bitmaps to select the operating interface mode for optical SFP modules, rather than using the linkmode bitmaps. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--drivers/net/phy/phylink.c56
1 files changed, 49 insertions, 7 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index a0a21cf530f4..c721ef6dda2e 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -2152,6 +2152,41 @@ 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_USXGMII,
+ PHY_INTERFACE_MODE_10GBASER,
+ PHY_INTERFACE_MODE_10GKR,
+ PHY_INTERFACE_MODE_2500BASEX,
+ PHY_INTERFACE_MODE_SGMII,
+ PHY_INTERFACE_MODE_1000BASEX,
+};
+
+static phy_interface_t phylink_select_interface(struct phylink *pl,
+ const unsigned long *intf,
+ const char *intf_name)
+{
+ DECLARE_PHY_INTERFACE_MASK(u);
+ phy_interface_t interface;
+ size_t i;
+
+ phy_interface_and(u, intf, pl->config->supported_interfaces);
+
+ interface = PHY_INTERFACE_MODE_NA;
+ for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++)
+ if (test_bit(phylink_sfp_interface_preference[i], u)) {
+ interface = phylink_sfp_interface_preference[i];
+ break;
+ }
+
+ phylink_info(pl, "interfaces=[mac=%*pbl %s=%*pbl] selected %d (%s)\n",
+ (int)PHY_INTERFACE_MODE_MAX,
+ pl->config->supported_interfaces,
+ intf_name, (int)PHY_INTERFACE_MODE_MAX, intf,
+ interface, phy_modes(interface));
+
+ return interface;
+}
+
static int phylink_sfp_config(struct phylink *pl, u8 mode,
const unsigned long *supported,
const unsigned long *advertising)
@@ -2234,25 +2269,33 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode,
return ret;
}
+static int phylink_sfp_config_nophy(struct phylink *pl)
+{
+ if (!phy_interface_empty(pl->config->supported_interfaces))
+ phylink_select_interface(pl, pl->sfp_interfaces, "sfp");
+
+ return phylink_sfp_config(pl, MLO_AN_INBAND,
+ pl->sfp_support, pl->sfp_support);
+}
+
static int phylink_sfp_module_insert(void *upstream,
const struct sfp_eeprom_id *id)
{
struct phylink *pl = upstream;
- unsigned long *support = pl->sfp_support;
ASSERT_RTNL();
- linkmode_zero(support);
+ linkmode_zero(pl->sfp_support);
phy_interface_zero(pl->sfp_interfaces);
- sfp_parse_support(pl->sfp_bus, id, support, pl->sfp_interfaces);
- pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support);
+ sfp_parse_support(pl->sfp_bus, id, pl->sfp_support, pl->sfp_interfaces);
+ pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, pl->sfp_support);
/* If this module may have a PHY connecting later, defer until later */
pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id);
if (pl->sfp_may_have_phy)
return 0;
- return phylink_sfp_config(pl, MLO_AN_INBAND, support, support);
+ return phylink_sfp_config_nophy(pl);
}
static int phylink_sfp_module_start(void *upstream)
@@ -2271,8 +2314,7 @@ static int phylink_sfp_module_start(void *upstream)
if (!pl->sfp_may_have_phy)
return 0;
- return phylink_sfp_config(pl, MLO_AN_INBAND,
- pl->sfp_support, pl->sfp_support);
+ return phylink_sfp_config_nophy(pl);
}
static void phylink_sfp_module_stop(void *upstream)