mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
net: phylink: Update SFP selected interface on advertising changes
Currently changes to the advertising state via ethtool do not cause any reselection of the configured interface mode after the SFP is already inserted and initially configured. While it is not typical to change the advertised link modes for an interface using an SFP in certain use cases it is desirable. In the case of a SFP port that is capable of handling both SFP and SFP+ modules it will automatically select between 1G and 10G modes depending on the supported mode of the SFP. However if the SFP module is capable of working in multiple modes (e.g. a SFP+ DAC that can operate at 1G or 10G), one end of the cable may be attached to a SFP 1000base-x port thus the SFP+ end must be manually configured to the 1000base-x mode in order for the link to be established. This change causes the ethtool setting of advertised mode changes to reselect the interface mode so that the link can be established. Additionally when a module is inserted the advertising mode is reset to match the supported modes of the module. Signed-off-by: Nathan Rossi <nathan.rossi@digi.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d7e203ffd3
commit
ea269a6f72
@ -1607,6 +1607,32 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
|
||||
if (config.an_enabled && phylink_is_empty_linkmode(config.advertising))
|
||||
return -EINVAL;
|
||||
|
||||
/* If this link is with an SFP, ensure that changes to advertised modes
|
||||
* also cause the associated interface to be selected such that the
|
||||
* link can be configured correctly.
|
||||
*/
|
||||
if (pl->sfp_port && pl->sfp_bus) {
|
||||
config.interface = sfp_select_interface(pl->sfp_bus,
|
||||
config.advertising);
|
||||
if (config.interface == PHY_INTERFACE_MODE_NA) {
|
||||
phylink_err(pl,
|
||||
"selection of interface failed, advertisement %*pb\n",
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS,
|
||||
config.advertising);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Revalidate with the selected interface */
|
||||
linkmode_copy(support, pl->supported);
|
||||
if (phylink_validate(pl, support, &config)) {
|
||||
phylink_err(pl, "validation of %s/%s with support %*pb failed\n",
|
||||
phylink_an_mode_str(pl->cur_link_an_mode),
|
||||
phy_modes(config.interface),
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS, support);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&pl->state_mutex);
|
||||
pl->link_config.speed = config.speed;
|
||||
pl->link_config.duplex = config.duplex;
|
||||
@ -2186,7 +2212,9 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode,
|
||||
if (phy_interface_mode_is_8023z(iface) && pl->phydev)
|
||||
return -EINVAL;
|
||||
|
||||
changed = !linkmode_equal(pl->supported, support);
|
||||
changed = !linkmode_equal(pl->supported, support) ||
|
||||
!linkmode_equal(pl->link_config.advertising,
|
||||
config.advertising);
|
||||
if (changed) {
|
||||
linkmode_copy(pl->supported, support);
|
||||
linkmode_copy(pl->link_config.advertising, config.advertising);
|
||||
|
Loading…
Reference in New Issue
Block a user