Skip to content

Commit

Permalink
mlxsw: Only advertise link modes supported by both driver and device
Browse files Browse the repository at this point in the history
[ Upstream commit 1601559 ]

During port creation the driver instructs the device to advertise all
the supported link modes queried from the device.

Since cited commit not all the link modes supported by the device are
supported by the driver. This can result in the device negotiating a
link mode that is not recognized by the driver causing ethtool to show
an unsupported speed:

$ ethtool swp1
...
Speed: Unknown!

This is especially problematic when the netdev is enslaved to a bond, as
the bond driver uses unknown speed as an indication that the link is
down:

[13048.900895] net_ratelimit: 86 callbacks suppressed
[13048.900902] t_bond0: (slave swp52): failed to get link speed/duplex
[13048.912160] t_bond0: (slave swp49): failed to get link speed/duplex

Fix this by making sure that only link modes that are supported by both
the device and the driver are advertised.

Fixes: b97cd89 ("mlxsw: Remove 56G speed support")
Signed-off-by: Amit Cohen <amcohen@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Amit Cohen authored and gregkh committed Nov 1, 2020
1 parent f267b0a commit d021dd2
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 2 deletions.
9 changes: 7 additions & 2 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Expand Up @@ -1546,11 +1546,14 @@ mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port)
u32 eth_proto_cap, eth_proto_admin, eth_proto_oper;
const struct mlxsw_sp_port_type_speed_ops *ops;
char ptys_pl[MLXSW_REG_PTYS_LEN];
u32 eth_proto_cap_masked;
int err;

ops = mlxsw_sp->port_type_speed_ops;

/* Set advertised speeds to supported speeds. */
/* Set advertised speeds to speeds supported by both the driver
* and the device.
*/
ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
0, false);
err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
Expand All @@ -1559,8 +1562,10 @@ mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port)

ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, &eth_proto_cap,
&eth_proto_admin, &eth_proto_oper);
eth_proto_cap_masked = ops->ptys_proto_cap_masked_get(eth_proto_cap);
ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
eth_proto_cap, mlxsw_sp_port->link.autoneg);
eth_proto_cap_masked,
mlxsw_sp_port->link.autoneg);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
}

Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Expand Up @@ -340,6 +340,7 @@ struct mlxsw_sp_port_type_speed_ops {
u32 *p_eth_proto_cap,
u32 *p_eth_proto_admin,
u32 *p_eth_proto_oper);
u32 (*ptys_proto_cap_masked_get)(u32 eth_proto_cap);
};

static inline struct net_device *
Expand Down
30 changes: 30 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c
Expand Up @@ -1208,6 +1208,20 @@ mlxsw_sp1_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,
p_eth_proto_oper);
}

static u32 mlxsw_sp1_ptys_proto_cap_masked_get(u32 eth_proto_cap)
{
u32 ptys_proto_cap_masked = 0;
int i;

for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
if (mlxsw_sp1_port_link_mode[i].mask & eth_proto_cap)
ptys_proto_cap_masked |=
mlxsw_sp1_port_link_mode[i].mask;
}

return ptys_proto_cap_masked;
}

const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops = {
.from_ptys_supported_port = mlxsw_sp1_from_ptys_supported_port,
.from_ptys_link = mlxsw_sp1_from_ptys_link,
Expand All @@ -1217,6 +1231,7 @@ const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops = {
.to_ptys_speed = mlxsw_sp1_to_ptys_speed,
.reg_ptys_eth_pack = mlxsw_sp1_reg_ptys_eth_pack,
.reg_ptys_eth_unpack = mlxsw_sp1_reg_ptys_eth_unpack,
.ptys_proto_cap_masked_get = mlxsw_sp1_ptys_proto_cap_masked_get,
};

static const enum ethtool_link_mode_bit_indices
Expand Down Expand Up @@ -1632,6 +1647,20 @@ mlxsw_sp2_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,
p_eth_proto_admin, p_eth_proto_oper);
}

static u32 mlxsw_sp2_ptys_proto_cap_masked_get(u32 eth_proto_cap)
{
u32 ptys_proto_cap_masked = 0;
int i;

for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
if (mlxsw_sp2_port_link_mode[i].mask & eth_proto_cap)
ptys_proto_cap_masked |=
mlxsw_sp2_port_link_mode[i].mask;
}

return ptys_proto_cap_masked;
}

const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops = {
.from_ptys_supported_port = mlxsw_sp2_from_ptys_supported_port,
.from_ptys_link = mlxsw_sp2_from_ptys_link,
Expand All @@ -1641,4 +1670,5 @@ const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops = {
.to_ptys_speed = mlxsw_sp2_to_ptys_speed,
.reg_ptys_eth_pack = mlxsw_sp2_reg_ptys_eth_pack,
.reg_ptys_eth_unpack = mlxsw_sp2_reg_ptys_eth_unpack,
.ptys_proto_cap_masked_get = mlxsw_sp2_ptys_proto_cap_masked_get,
};

0 comments on commit d021dd2

Please sign in to comment.