mlxsw: spectrum_ethtool: Introduce ptys_max_speed callback
authorPetr Machata <petrm@nvidia.com>
Sun, 13 Sep 2020 15:46:06 +0000 (18:46 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 14 Sep 2020 21:37:30 +0000 (14:37 -0700)
The SBIB register configures the size of an internal buffer that the
Spectrum ASICs use when mirroring traffic on egress. This size should be
taken into account when validating that the port headroom buffers are not
larger than the chip can handle. Up until now this was not done, which is
incidentally not a problem, because the priority group buffers that mlxsw
auto-configures are small enough that the boundary condition could not be
violated.

When dcbnl_setbuffer is implemented, the user gets control over sizes of PG
buffers, and they might overshoot the headroom capacity. However the size
of the SBIB buffer depends on port speed, which cannot be vetoed. There is
obviously no way to retroactively push back on requests for overlarge PG
buffers, or reject an overlarge MTU, or cancel losslessness of a certain
PG.

Therefore, instead of taking into account the current speed when
calculating SBIB buffer size, take into account the maximum speed that a
port with given Ethernet protocol capabilities can have.

To that end, add a new ethtool callback, ptys_max_speed, which determines
this maximum speed.

Signed-off-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c

index 5240bf1..007e97e 100644 (file)
@@ -331,6 +331,7 @@ struct mlxsw_sp_port_type_speed_ops {
        void (*from_ptys_speed_duplex)(struct mlxsw_sp *mlxsw_sp,
                                       bool carrier_ok, u32 ptys_eth_proto,
                                       struct ethtool_link_ksettings *cmd);
+       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, u8 width,
                                   const struct ethtool_link_ksettings *cmd);
        u32 (*to_ptys_speed)(struct mlxsw_sp *mlxsw_sp, u8 width, u32 speed);
index f007e58..6ee0479 100644 (file)
@@ -1162,6 +1162,27 @@ mlxsw_sp1_from_ptys_speed_duplex(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
                cmd->base.duplex = DUPLEX_FULL;
 }
 
+static int mlxsw_sp1_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)
+{
+       u32 eth_proto_cap;
+       u32 max_speed = 0;
+       int err;
+       int i;
+
+       err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, &eth_proto_cap, NULL, NULL, NULL);
+       if (err)
+               return err;
+
+       for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
+               if ((eth_proto_cap & mlxsw_sp1_port_link_mode[i].mask) &&
+                   mlxsw_sp1_port_link_mode[i].speed > max_speed)
+                       max_speed = mlxsw_sp1_port_link_mode[i].speed;
+       }
+
+       *p_max_speed = max_speed;
+       return 0;
+}
+
 static u32
 mlxsw_sp1_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp, u8 width,
                              const struct ethtool_link_ksettings *cmd)
@@ -1211,6 +1232,7 @@ const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops = {
        .from_ptys_link                 = mlxsw_sp1_from_ptys_link,
        .from_ptys_speed                = mlxsw_sp1_from_ptys_speed,
        .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,
        .reg_ptys_eth_pack              = mlxsw_sp1_reg_ptys_eth_pack,
@@ -1548,6 +1570,27 @@ mlxsw_sp2_from_ptys_speed_duplex(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
                cmd->base.duplex = DUPLEX_FULL;
 }
 
+static int mlxsw_sp2_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)
+{
+       u32 eth_proto_cap;
+       u32 max_speed = 0;
+       int err;
+       int i;
+
+       err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, &eth_proto_cap, NULL, NULL, NULL);
+       if (err)
+               return err;
+
+       for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
+               if ((eth_proto_cap & mlxsw_sp2_port_link_mode[i].mask) &&
+                   mlxsw_sp2_port_link_mode[i].speed > max_speed)
+                       max_speed = mlxsw_sp2_port_link_mode[i].speed;
+       }
+
+       *p_max_speed = max_speed;
+       return 0;
+}
+
 static bool
 mlxsw_sp2_test_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode,
                           const unsigned long *mode)
@@ -1617,6 +1660,7 @@ const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops = {
        .from_ptys_link                 = mlxsw_sp2_from_ptys_link,
        .from_ptys_speed                = mlxsw_sp2_from_ptys_speed,
        .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,
        .reg_ptys_eth_pack              = mlxsw_sp2_reg_ptys_eth_pack,