]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
mlxsw: ethtool: Add support for setting lanes when autoneg is off
authorDanielle Ratson <danieller@nvidia.com>
Tue, 2 Feb 2021 18:06:10 +0000 (20:06 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 4 Feb 2021 02:37:29 +0000 (18:37 -0800)
Currently, when auto negotiation is set to off, the user can force a
specific speed or both speed and duplex. The user cannot influence the
number of lanes that will be forced.

Add support for setting speed along with lanes so one would be able
to choose how many lanes will be forced.

When lanes parameter is passed from user space, choose the link mode
that its actual width equals to it.
Otherwise, the default link mode will be the one that supports the width
of the port.

Signed-off-by: Danielle Ratson <danieller@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c

index 1aba500af129aac17562e178863539271a5d097e..9ded4d1b1a9f4fe982577edac018e2ca63a1895c 100644 (file)
@@ -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,
index 809ea7be77ccbe9ddf0c48676f15ae060551df10..15c6e5af8ee521126e43c3a375d9acae446e3216 100644 (file)
@@ -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,