mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 20:02:10 -04:00
Merge branch 'net-phylink-support-autoneg-configuration-for-sfps'
Russell King says: ==================== net: phylink: support !autoneg configuration for SFPs This series comes from discussion during a patch series that was posted at the beginning of April, but these patches were never posted (I was too busy!) We restrict ->sfp_interfaces to those that the host system supports, and ensure that ->sfp_interfaces is cleared when a SFP is removed. We then add phylink_sfp_select_interface_speed() which will select an appropriate interface from ->sfp_interfaces for the speed, and use that in our phylink_ethtool_ksettings_set() when a SFP bus is present on a directly connected host (not with a PHY.) ==================== Link: https://patch.msgid.link/aGT_hoBELDysGbrp@shell.armlinux.org.uk Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -2709,6 +2709,39 @@ static phy_interface_t phylink_sfp_select_interface(struct phylink *pl,
|
||||
return interface;
|
||||
}
|
||||
|
||||
static phy_interface_t phylink_sfp_select_interface_speed(struct phylink *pl,
|
||||
u32 speed)
|
||||
{
|
||||
phy_interface_t best_interface = PHY_INTERFACE_MODE_NA;
|
||||
phy_interface_t interface;
|
||||
u32 max_speed;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++) {
|
||||
interface = phylink_sfp_interface_preference[i];
|
||||
if (!test_bit(interface, pl->sfp_interfaces))
|
||||
continue;
|
||||
|
||||
max_speed = phylink_interface_max_speed(interface);
|
||||
|
||||
/* The logic here is: if speed == max_speed, then we've found
|
||||
* the best interface. Otherwise we find the interface that
|
||||
* can just support the requested speed.
|
||||
*/
|
||||
if (max_speed >= speed)
|
||||
best_interface = interface;
|
||||
|
||||
if (max_speed <= speed)
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_interface == PHY_INTERFACE_MODE_NA)
|
||||
phylink_err(pl, "selection of interface failed, speed %u\n",
|
||||
speed);
|
||||
|
||||
return best_interface;
|
||||
}
|
||||
|
||||
static void phylink_merge_link_mode(unsigned long *dst, const unsigned long *b)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask);
|
||||
@@ -2911,8 +2944,14 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
|
||||
* link can be configured correctly.
|
||||
*/
|
||||
if (pl->sfp_bus) {
|
||||
config.interface = phylink_sfp_select_interface(pl,
|
||||
if (kset->base.autoneg == AUTONEG_ENABLE)
|
||||
config.interface =
|
||||
phylink_sfp_select_interface(pl,
|
||||
config.advertising);
|
||||
else
|
||||
config.interface =
|
||||
phylink_sfp_select_interface_speed(pl,
|
||||
config.speed);
|
||||
if (config.interface == PHY_INTERFACE_MODE_NA)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -3536,6 +3575,8 @@ static int phylink_sfp_config_phy(struct phylink *pl, struct phy_device *phy)
|
||||
struct phylink_link_state config;
|
||||
int ret;
|
||||
|
||||
/* We're not using pl->sfp_interfaces, so clear it. */
|
||||
phy_interface_zero(pl->sfp_interfaces);
|
||||
linkmode_copy(support, phy->supported);
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
@@ -3582,7 +3623,6 @@ static int phylink_sfp_config_phy(struct phylink *pl, struct phy_device *phy)
|
||||
static int phylink_sfp_config_optical(struct phylink *pl)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(support);
|
||||
DECLARE_PHY_INTERFACE_MASK(interfaces);
|
||||
struct phylink_link_state config;
|
||||
phy_interface_t interface;
|
||||
int ret;
|
||||
@@ -3596,9 +3636,9 @@ static int phylink_sfp_config_optical(struct phylink *pl)
|
||||
/* Find the union of the supported interfaces by the PCS/MAC and
|
||||
* the SFP module.
|
||||
*/
|
||||
phy_interface_and(interfaces, pl->config->supported_interfaces,
|
||||
phy_interface_and(pl->sfp_interfaces, pl->config->supported_interfaces,
|
||||
pl->sfp_interfaces);
|
||||
if (phy_interface_empty(interfaces)) {
|
||||
if (phy_interface_empty(pl->sfp_interfaces)) {
|
||||
phylink_err(pl, "unsupported SFP module: no common interface modes\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -3614,14 +3654,14 @@ static int phylink_sfp_config_optical(struct phylink *pl)
|
||||
* mask to only those link modes that can be supported.
|
||||
*/
|
||||
ret = phylink_validate_mask(pl, NULL, pl->sfp_support, &config,
|
||||
interfaces);
|
||||
pl->sfp_interfaces);
|
||||
if (ret) {
|
||||
phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n",
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS, support);
|
||||
return ret;
|
||||
}
|
||||
|
||||
interface = phylink_choose_sfp_interface(pl, interfaces);
|
||||
interface = phylink_choose_sfp_interface(pl, pl->sfp_interfaces);
|
||||
if (interface == PHY_INTERFACE_MODE_NA) {
|
||||
phylink_err(pl, "failed to select SFP interface\n");
|
||||
return -EINVAL;
|
||||
@@ -3674,6 +3714,13 @@ static int phylink_sfp_module_insert(void *upstream,
|
||||
return phylink_sfp_config_optical(pl);
|
||||
}
|
||||
|
||||
static void phylink_sfp_module_remove(void *upstream)
|
||||
{
|
||||
struct phylink *pl = upstream;
|
||||
|
||||
phy_interface_zero(pl->sfp_interfaces);
|
||||
}
|
||||
|
||||
static int phylink_sfp_module_start(void *upstream)
|
||||
{
|
||||
struct phylink *pl = upstream;
|
||||
@@ -3758,6 +3805,7 @@ static const struct sfp_upstream_ops sfp_phylink_ops = {
|
||||
.attach = phylink_sfp_attach,
|
||||
.detach = phylink_sfp_detach,
|
||||
.module_insert = phylink_sfp_module_insert,
|
||||
.module_remove = phylink_sfp_module_remove,
|
||||
.module_start = phylink_sfp_module_start,
|
||||
.module_stop = phylink_sfp_module_stop,
|
||||
.link_up = phylink_sfp_link_up,
|
||||
|
||||
Reference in New Issue
Block a user