Some copper SFP modules support both SGMII and 1000BaseX, but some
drivers/devices only support the 1000BaseX mode. Currently SGMII mode is
always being selected as the desired mode for such modules, and this
fails if the controller doesn't support SGMII. Add a fallback for this
case by trying 1000BaseX instead if the controller rejects SGMII mode.

Signed-off-by: Robert Hancock <hanc...@sedsystems.ca>
---
 drivers/net/phy/phylink.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 68d0a89..4fd72c2 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1626,6 +1626,7 @@ static int phylink_sfp_module_insert(void *upstream,
 {
        struct phylink *pl = upstream;
        __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(orig_support) = { 0, };
        struct phylink_link_state config;
        phy_interface_t iface;
        int ret = 0;
@@ -1635,6 +1636,7 @@ static int phylink_sfp_module_insert(void *upstream,
        ASSERT_RTNL();
 
        sfp_parse_support(pl->sfp_bus, id, support);
+       linkmode_copy(orig_support, support);
        port = sfp_parse_port(pl->sfp_bus, id, support);
 
        memset(&config, 0, sizeof(config));
@@ -1663,6 +1665,25 @@ static int phylink_sfp_module_insert(void *upstream,
 
        config.interface = iface;
        ret = phylink_validate(pl, support, &config);
+
+       if (ret && iface == PHY_INTERFACE_MODE_SGMII &&
+           phylink_test(orig_support, 1000baseX_Full)) {
+               /* Copper modules may select SGMII but the interface may not
+                * support that mode, try 1000BaseX if supported.
+                */
+
+               netdev_warn(pl->netdev, "validation of %s/%s with support %*pb "
+                           "failed: %d, trying 1000BaseX\n",
+                           phylink_an_mode_str(MLO_AN_INBAND),
+                           phy_modes(config.interface),
+                           __ETHTOOL_LINK_MODE_MASK_NBITS, orig_support, ret);
+               iface = PHY_INTERFACE_MODE_1000BASEX;
+               config.interface = iface;
+               linkmode_copy(config.advertising, orig_support);
+               linkmode_copy(support, orig_support);
+               ret = phylink_validate(pl, support, &config);
+       }
+
        if (ret) {
                phylink_err(pl, "validation of %s/%s with support %*pb failed: 
%d\n",
                            phylink_an_mode_str(MLO_AN_INBAND),
-- 
1.8.3.1

Reply via email to