summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2019-11-08 17:19:16 +0000
committerRussell King <rmk+kernel@armlinux.org.uk>2020-01-27 10:33:10 +0000
commitb24700074fa5e25bc70a33cd71c565e66f7aa62b (patch)
tree413a07c495c2b566588b1d8c8fd7da61a7da95ac
parent949e063b3cd9d8b7c694672c892c791d9c4d81c2 (diff)
net: phylink: make Broadcom BCM84881 based SFPs work
The Broadcom BCM84881 does not appear to send the SGMII control word when operating in SGMII mode, which causes network adapters to fail to link with the PHY, or decide to operate at fixed 1G speed, even if the PHY negotiated 100M. Work around this by detecting the Broadcom BCM84881 and switch to phy mode rather than inband mode. Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--drivers/net/phy/phylink.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 88afc98a2aa6..e9f37753325f 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1839,10 +1839,20 @@ static void phylink_sfp_link_up(void *upstream)
phylink_run_resolve(pl);
}
+/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
+ * or 802.3z control word, so inband will not work.
+ */
+static bool phylink_phy_no_inband(struct phy_device *phy)
+{
+ return phy->is_c45 &&
+ (phy->c45_ids.device_ids[1] & 0xfffffff0) == 0xae025150;
+}
+
static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
{
struct phylink *pl = upstream;
phy_interface_t interface;
+ u8 mode;
int ret;
/*
@@ -1854,9 +1864,13 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
*/
phy_support_asym_pause(phy);
+ if (phylink_phy_no_inband(phy))
+ mode = MLO_AN_PHY;
+ else
+ mode = MLO_AN_INBAND;
+
/* Do the initial configuration */
- ret = phylink_sfp_config(pl, MLO_AN_INBAND, phy->supported,
- phy->advertising);
+ ret = phylink_sfp_config(pl, mode, phy->supported, phy->advertising);
if (ret < 0)
return ret;