diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 1aba500af129..9ded4d1b1a9f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -336,7 +336,8 @@ struct mlxsw_sp_port_type_speed_ops { int (*ptys_max_speed)(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed); u32 (*to_ptys_advert_link)(struct mlxsw_sp *mlxsw_sp, const struct ethtool_link_ksettings *cmd); - u32 (*to_ptys_speed)(struct mlxsw_sp *mlxsw_sp, u8 width, u32 speed); + u32 (*to_ptys_speed_lanes)(struct mlxsw_sp *mlxsw_sp, u8 width, + const struct ethtool_link_ksettings *cmd); void (*reg_ptys_eth_pack)(struct mlxsw_sp *mlxsw_sp, char *payload, u8 local_port, u32 proto_admin, bool autoneg); void (*reg_ptys_eth_unpack)(struct mlxsw_sp *mlxsw_sp, char *payload, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c index 809ea7be77cc..15c6e5af8ee5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c @@ -996,12 +996,12 @@ mlxsw_sp_port_set_link_ksettings(struct net_device *dev, autoneg = cmd->base.autoneg == AUTONEG_ENABLE; eth_proto_new = autoneg ? ops->to_ptys_advert_link(mlxsw_sp, cmd) : - ops->to_ptys_speed(mlxsw_sp, mlxsw_sp_port->mapping.width, - cmd->base.speed); + ops->to_ptys_speed_lanes(mlxsw_sp, mlxsw_sp_port->mapping.width, + cmd); eth_proto_new = eth_proto_new & eth_proto_cap; if (!eth_proto_new) { - netdev_err(dev, "No supported speed requested\n"); + netdev_err(dev, "No supported speed or lanes requested\n"); return -EINVAL; } @@ -1060,20 +1060,21 @@ mlxsw_sp_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info) } const struct ethtool_ops mlxsw_sp_port_ethtool_ops = { - .get_drvinfo = mlxsw_sp_port_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_link_ext_state = mlxsw_sp_port_get_link_ext_state, - .get_pauseparam = mlxsw_sp_port_get_pauseparam, - .set_pauseparam = mlxsw_sp_port_set_pauseparam, - .get_strings = mlxsw_sp_port_get_strings, - .set_phys_id = mlxsw_sp_port_set_phys_id, - .get_ethtool_stats = mlxsw_sp_port_get_stats, - .get_sset_count = mlxsw_sp_port_get_sset_count, - .get_link_ksettings = mlxsw_sp_port_get_link_ksettings, - .set_link_ksettings = mlxsw_sp_port_set_link_ksettings, - .get_module_info = mlxsw_sp_get_module_info, - .get_module_eeprom = mlxsw_sp_get_module_eeprom, - .get_ts_info = mlxsw_sp_get_ts_info, + .cap_link_lanes_supported = true, + .get_drvinfo = mlxsw_sp_port_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_link_ext_state = mlxsw_sp_port_get_link_ext_state, + .get_pauseparam = mlxsw_sp_port_get_pauseparam, + .set_pauseparam = mlxsw_sp_port_set_pauseparam, + .get_strings = mlxsw_sp_port_get_strings, + .set_phys_id = mlxsw_sp_port_set_phys_id, + .get_ethtool_stats = mlxsw_sp_port_get_stats, + .get_sset_count = mlxsw_sp_port_get_sset_count, + .get_link_ksettings = mlxsw_sp_port_get_link_ksettings, + .set_link_ksettings = mlxsw_sp_port_set_link_ksettings, + .get_module_info = mlxsw_sp_get_module_info, + .get_module_eeprom = mlxsw_sp_get_module_eeprom, + .get_ts_info = mlxsw_sp_get_ts_info, }; struct mlxsw_sp1_port_link_mode { @@ -1271,14 +1272,17 @@ mlxsw_sp1_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp, return ptys_proto; } -static u32 mlxsw_sp1_to_ptys_speed(struct mlxsw_sp *mlxsw_sp, u8 width, - u32 speed) +static u32 mlxsw_sp1_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width, + const struct ethtool_link_ksettings *cmd) { u32 ptys_proto = 0; int i; + if (cmd->lanes > width) + return ptys_proto; + for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { - if (speed == mlxsw_sp1_port_link_mode[i].speed) + if (cmd->base.speed == mlxsw_sp1_port_link_mode[i].speed) ptys_proto |= mlxsw_sp1_port_link_mode[i].mask; } return ptys_proto; @@ -1321,7 +1325,7 @@ const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops = { .from_ptys_speed_duplex = mlxsw_sp1_from_ptys_speed_duplex, .ptys_max_speed = mlxsw_sp1_ptys_max_speed, .to_ptys_advert_link = mlxsw_sp1_to_ptys_advert_link, - .to_ptys_speed = mlxsw_sp1_to_ptys_speed, + .to_ptys_speed_lanes = mlxsw_sp1_to_ptys_speed_lanes, .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, @@ -1483,7 +1487,8 @@ struct mlxsw_sp2_port_link_mode { int m_ethtool_len; u32 mask; u32 speed; - u8 mask_width; + u32 width; + u8 mask_sup_width; }; static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { @@ -1491,105 +1496,117 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_SGMII_100M, .mask_ethtool = mlxsw_sp2_mask_ethtool_sgmii_100m, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | MLXSW_SP_PORT_MASK_WIDTH_4X | MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_100, + .width = 1, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_1000BASE_X_SGMII, .mask_ethtool = mlxsw_sp2_mask_ethtool_1000base_x_sgmii, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | MLXSW_SP_PORT_MASK_WIDTH_4X | MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_1000, + .width = 1, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_5GBASE_R, .mask_ethtool = mlxsw_sp2_mask_ethtool_5gbase_r, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | MLXSW_SP_PORT_MASK_WIDTH_4X | MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_5000, + .width = 1, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XFI_XAUI_1_10G, .mask_ethtool = mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | MLXSW_SP_PORT_MASK_WIDTH_4X | MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_10000, + .width = 1, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XLAUI_4_XLPPI_4_40G, .mask_ethtool = mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X | MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_40000, + .width = 4, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_25GAUI_1_25GBASE_CR_KR, .mask_ethtool = mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | MLXSW_SP_PORT_MASK_WIDTH_4X | MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_25000, + .width = 1, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_2_LAUI_2_50GBASE_CR2_KR2, .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_2X | + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_2X | MLXSW_SP_PORT_MASK_WIDTH_4X | MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_50000, + .width = 2, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_1_LAUI_1_50GBASE_CR_KR, .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X, + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X, .speed = SPEED_50000, + .width = 1, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4, .mask_ethtool = mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X | MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_100000, + .width = 4, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2, .mask_ethtool = mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_2X, + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_2X, .speed = SPEED_100000, + .width = 2, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4, .mask_ethtool = mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X | MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_200000, + .width = 4, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8, .mask_ethtool = mlxsw_sp2_mask_ethtool_400gaui_8, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_8X, + .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_400000, + .width = 8, }, }; @@ -1707,17 +1724,36 @@ mlxsw_sp2_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp, return ptys_proto; } -static u32 mlxsw_sp2_to_ptys_speed(struct mlxsw_sp *mlxsw_sp, - u8 width, u32 speed) +static u32 mlxsw_sp2_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width, + const struct ethtool_link_ksettings *cmd) { u8 mask_width = mlxsw_sp_port_mask_width_get(width); + struct mlxsw_sp2_port_link_mode link_mode; u32 ptys_proto = 0; int i; + if (cmd->lanes > width) + return ptys_proto; + for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { - if ((speed == mlxsw_sp2_port_link_mode[i].speed) && - (mask_width & mlxsw_sp2_port_link_mode[i].mask_width)) - ptys_proto |= mlxsw_sp2_port_link_mode[i].mask; + if (cmd->base.speed == mlxsw_sp2_port_link_mode[i].speed) { + link_mode = mlxsw_sp2_port_link_mode[i]; + + if (!cmd->lanes) { + /* If number of lanes was not set by user space, + * choose the link mode that supports the width + * of the port. + */ + if (mask_width & link_mode.mask_sup_width) + ptys_proto |= link_mode.mask; + } else if (cmd->lanes == link_mode.width) { + /* Else if the number of lanes was set, choose + * the link mode that its actual width equals to + * it. + */ + ptys_proto |= link_mode.mask; + } + } } return ptys_proto; } @@ -1760,7 +1796,7 @@ const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops = { .from_ptys_speed_duplex = mlxsw_sp2_from_ptys_speed_duplex, .ptys_max_speed = mlxsw_sp2_ptys_max_speed, .to_ptys_advert_link = mlxsw_sp2_to_ptys_advert_link, - .to_ptys_speed = mlxsw_sp2_to_ptys_speed, + .to_ptys_speed_lanes = mlxsw_sp2_to_ptys_speed_lanes, .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,