| From 7adb5b2126bc013f0964ddaefad6ad1b132e86c3 Mon Sep 17 00:00:00 2001 | 
 | From: Russell King <rmk+kernel@armlinux.org.uk> | 
 | Date: Wed, 11 Dec 2019 10:56:50 +0000 | 
 | Subject: [PATCH] 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> | 
 | Signed-off-by: David S. Miller <davem@davemloft.net> | 
 | --- | 
 |  drivers/net/phy/phylink.c | 18 ++++++++++++++++-- | 
 |  1 file changed, 16 insertions(+), 2 deletions(-) | 
 |  | 
 | --- a/drivers/net/phy/phylink.c | 
 | +++ b/drivers/net/phy/phylink.c | 
 | @@ -1842,10 +1842,20 @@ static void phylink_sfp_link_up(void *up | 
 |  	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; | 
 |   | 
 |  	/* | 
 | @@ -1857,9 +1867,13 @@ static int phylink_sfp_connect_phy(void | 
 |  	 */ | 
 |  	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; | 
 |   |