diff options
| author | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
| commit | 1ac731c529cd4d6adbce134754b51ff7d822b145 (patch) | |
| tree | 143ab3f35ca5f3b69f583c84e6964b17139c2ec1 /drivers/net/phy/phylink.c | |
| parent | 07b4c950f27bef0362dc6ad7ee713aab61d58149 (diff) | |
| parent | 54116d442e001e1b6bd482122043b1870998a1f3 (diff) | |
Merge branch 'next' into for-linus
Prepare input updates for 6.6 merge window.
Diffstat (limited to 'drivers/net/phy/phylink.c')
| -rw-r--r-- | drivers/net/phy/phylink.c | 106 | 
1 files changed, 82 insertions, 24 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 1a2f074685fa..5efdeb59f4b2 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -188,6 +188,7 @@ static int phylink_interface_max_speed(phy_interface_t interface)  	case PHY_INTERFACE_MODE_RGMII_ID:  	case PHY_INTERFACE_MODE_RGMII:  	case PHY_INTERFACE_MODE_QSGMII: +	case PHY_INTERFACE_MODE_QUSGMII:  	case PHY_INTERFACE_MODE_SGMII:  	case PHY_INTERFACE_MODE_GMII:  		return SPEED_1000; @@ -204,7 +205,6 @@ static int phylink_interface_max_speed(phy_interface_t interface)  	case PHY_INTERFACE_MODE_10GBASER:  	case PHY_INTERFACE_MODE_10GKR:  	case PHY_INTERFACE_MODE_USXGMII: -	case PHY_INTERFACE_MODE_QUSGMII:  		return SPEED_10000;  	case PHY_INTERFACE_MODE_25GBASER: @@ -843,7 +843,6 @@ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)  		phylink_set(pl->supported, Autoneg);  		phylink_set(pl->supported, Asym_Pause);  		phylink_set(pl->supported, Pause); -		pl->link_config.an_enabled = true;  		pl->cfg_link_an_mode = MLO_AN_INBAND;  		switch (pl->link_config.interface) { @@ -945,9 +944,6 @@ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)  				    "failed to validate link configuration for in-band status\n");  			return -EINVAL;  		} - -		/* Check if MAC/PCS also supports Autoneg. */ -		pl->link_config.an_enabled = phylink_test(pl->supported, Autoneg);  	}  	return 0; @@ -957,7 +953,8 @@ static void phylink_apply_manual_flow(struct phylink *pl,  				      struct phylink_link_state *state)  {  	/* If autoneg is disabled, pause AN is also disabled */ -	if (!state->an_enabled) +	if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, +			       state->advertising))  		state->pause &= ~MLO_PAUSE_AN;  	/* Manual configuration of pause modes */ @@ -997,21 +994,22 @@ static void phylink_mac_config(struct phylink *pl,  			       const struct phylink_link_state *state)  {  	phylink_dbg(pl, -		    "%s: mode=%s/%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n", +		    "%s: mode=%s/%s/%s/%s/%s adv=%*pb pause=%02x link=%u\n",  		    __func__, phylink_an_mode_str(pl->cur_link_an_mode),  		    phy_modes(state->interface),  		    phy_speed_to_str(state->speed),  		    phy_duplex_to_str(state->duplex),  		    phy_rate_matching_to_str(state->rate_matching),  		    __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising, -		    state->pause, state->link, state->an_enabled); +		    state->pause, state->link);  	pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, state);  }  static void phylink_mac_pcs_an_restart(struct phylink *pl)  { -	if (pl->link_config.an_enabled && +	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, +			      pl->link_config.advertising) &&  	    phy_interface_mode_is_8023z(pl->link_config.interface) &&  	    phylink_autoneg_inband(pl->cur_link_an_mode)) {  		if (pl->pcs) @@ -1138,9 +1136,9 @@ static void phylink_mac_pcs_get_state(struct phylink *pl,  	linkmode_copy(state->advertising, pl->link_config.advertising);  	linkmode_zero(state->lp_advertising);  	state->interface = pl->link_config.interface; -	state->an_enabled = pl->link_config.an_enabled;  	state->rate_matching = pl->link_config.rate_matching; -	if (state->an_enabled) { +	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, +			      state->advertising)) {  		state->speed = SPEED_UNKNOWN;  		state->duplex = DUPLEX_UNKNOWN;  		state->pause = MLO_PAUSE_NONE; @@ -1531,7 +1529,6 @@ struct phylink *phylink_create(struct phylink_config *config,  	pl->link_config.pause = MLO_PAUSE_AN;  	pl->link_config.speed = SPEED_UNKNOWN;  	pl->link_config.duplex = DUPLEX_UNKNOWN; -	pl->link_config.an_enabled = true;  	pl->mac_ops = mac_ops;  	__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);  	timer_setup(&pl->link_poll, phylink_fixed_poll, 0); @@ -1586,6 +1583,25 @@ void phylink_destroy(struct phylink *pl)  }  EXPORT_SYMBOL_GPL(phylink_destroy); +/** + * phylink_expects_phy() - Determine if phylink expects a phy to be attached + * @pl: a pointer to a &struct phylink returned from phylink_create() + * + * When using fixed-link mode, or in-band mode with 1000base-X or 2500base-X, + * no PHY is needed. + * + * Returns true if phylink will be expecting a PHY. + */ +bool phylink_expects_phy(struct phylink *pl) +{ +	if (pl->cfg_link_an_mode == MLO_AN_FIXED || +	    (pl->cfg_link_an_mode == MLO_AN_INBAND && +	     phy_interface_mode_is_8023z(pl->link_config.interface))) +		return false; +	return true; +} +EXPORT_SYMBOL_GPL(phylink_expects_phy); +  static void phylink_phy_change(struct phy_device *phydev, bool up)  {  	struct phylink *pl = phydev->phylink; @@ -2136,8 +2152,9 @@ static void phylink_get_ksettings(const struct phylink_link_state *state,  		kset->base.speed = state->speed;  		kset->base.duplex = state->duplex;  	} -	kset->base.autoneg = state->an_enabled ? AUTONEG_ENABLE : -				AUTONEG_DISABLE; +	kset->base.autoneg = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, +					       state->advertising) ? +				AUTONEG_ENABLE : AUTONEG_DISABLE;  }  /** @@ -2209,6 +2226,12 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,  	ASSERT_RTNL();  	if (pl->phydev) { +		struct ethtool_link_ksettings phy_kset = *kset; + +		linkmode_and(phy_kset.link_modes.advertising, +			     phy_kset.link_modes.advertising, +			     pl->supported); +  		/* We can rely on phylib for this update; we also do not need  		 * to update the pl->link_config settings:  		 * - the configuration returned via ksettings_get() will come @@ -2227,11 +2250,10 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,  		 *   the presence of a PHY, this should not be changed as that  		 *   should be determined from the media side advertisement.  		 */ -		return phy_ethtool_ksettings_set(pl->phydev, kset); +		return phy_ethtool_ksettings_set(pl->phydev, &phy_kset);  	}  	config = pl->link_config; -  	/* Mask out unsupported advertisements */  	linkmode_and(config.advertising, kset->link_modes.advertising,  		     pl->supported); @@ -2284,9 +2306,8 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,  	/* We have ruled out the case with a PHY attached, and the  	 * fixed-link cases.  All that is left are in-band links.  	 */ -	config.an_enabled = kset->base.autoneg == AUTONEG_ENABLE;  	linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising, -			 config.an_enabled); +			 kset->base.autoneg == AUTONEG_ENABLE);  	/* If this link is with an SFP, ensure that changes to advertised modes  	 * also cause the associated interface to be selected such that the @@ -2320,13 +2341,14 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,  	}  	/* If autonegotiation is enabled, we must have an advertisement */ -	if (config.an_enabled && phylink_is_empty_linkmode(config.advertising)) +	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, +			      config.advertising) && +	    phylink_is_empty_linkmode(config.advertising))  		return -EINVAL;  	mutex_lock(&pl->state_mutex);  	pl->link_config.speed = config.speed;  	pl->link_config.duplex = config.duplex; -	pl->link_config.an_enabled = config.an_enabled;  	if (pl->link_config.interface != config.interface) {  		/* The interface changed, e.g. 1000base-X <-> 2500base-X */ @@ -2932,7 +2954,6 @@ static int phylink_sfp_config_phy(struct phylink *pl, u8 mode,  	config.speed = SPEED_UNKNOWN;  	config.duplex = DUPLEX_UNKNOWN;  	config.pause = MLO_PAUSE_AN; -	config.an_enabled = pl->link_config.an_enabled;  	/* Ignore errors if we're expecting a PHY to attach later */  	ret = phylink_validate(pl, support, &config); @@ -3001,7 +3022,6 @@ static int phylink_sfp_config_optical(struct phylink *pl)  	config.speed = SPEED_UNKNOWN;  	config.duplex = DUPLEX_UNKNOWN;  	config.pause = MLO_PAUSE_AN; -	config.an_enabled = true;  	/* For all the interfaces that are supported, reduce the sfp_support  	 * mask to only those link modes that can be supported. @@ -3279,6 +3299,41 @@ void phylink_decode_usxgmii_word(struct phylink_link_state *state,  EXPORT_SYMBOL_GPL(phylink_decode_usxgmii_word);  /** + * phylink_decode_usgmii_word() - decode the USGMII word from a MAC PCS + * @state: a pointer to a struct phylink_link_state. + * @lpa: a 16 bit value which stores the USGMII auto-negotiation word + * + * Helper for MAC PCS supporting the USGMII protocol and the auto-negotiation + * code word.  Decode the USGMII code word and populate the corresponding fields + * (speed, duplex) into the phylink_link_state structure. The structure for this + * word is the same as the USXGMII word, except it only supports speeds up to + * 1Gbps. + */ +static void phylink_decode_usgmii_word(struct phylink_link_state *state, +				       uint16_t lpa) +{ +	switch (lpa & MDIO_USXGMII_SPD_MASK) { +	case MDIO_USXGMII_10: +		state->speed = SPEED_10; +		break; +	case MDIO_USXGMII_100: +		state->speed = SPEED_100; +		break; +	case MDIO_USXGMII_1000: +		state->speed = SPEED_1000; +		break; +	default: +		state->link = false; +		return; +	} + +	if (lpa & MDIO_USXGMII_FULL_DUPLEX) +		state->duplex = DUPLEX_FULL; +	else +		state->duplex = DUPLEX_HALF; +} + +/**   * phylink_mii_c22_pcs_decode_state() - Decode MAC PCS state from MII registers   * @state: a pointer to a &struct phylink_link_state.   * @bmsr: The value of the %MII_BMSR register @@ -3300,7 +3355,8 @@ void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state,  	/* If there is no link or autonegotiation is disabled, the LP advertisement  	 * data is not meaningful, so don't go any further.  	 */ -	if (!state->link || !state->an_enabled) +	if (!state->link || !linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, +					       state->advertising))  		return;  	switch (state->interface) { @@ -3314,9 +3370,11 @@ void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state,  	case PHY_INTERFACE_MODE_SGMII:  	case PHY_INTERFACE_MODE_QSGMII: -	case PHY_INTERFACE_MODE_QUSGMII:  		phylink_decode_sgmii_word(state, lpa);  		break; +	case PHY_INTERFACE_MODE_QUSGMII: +		phylink_decode_usgmii_word(state, lpa); +		break;  	default:  		state->link = false;  |