Skip to content

Commit

Permalink
Merge branch 'mlxsw-Derive-SBIB-from-maximum-port-speed-and-MTU'
Browse files Browse the repository at this point in the history
Ido Schimmel says:

====================
mlxsw: Derive SBIB from maximum port speed & MTU

Petr says:

Internal buffer is a part of port headroom used for packets that are
mirrored due to triggers that the Spectrum ASIC considers "egress". Besides
ACL mirroring on port egresss this includes also packets mirrored due to
ECN marking.

This patchset changes the way the internal mirroring buffer is reserved.
Currently the buffer reflects port MTU and speed accurately. In the future,
mlxsw should support dcbnl_setbuffer hook to allow the users to set buffer
sizes by hand. In that case, there might not be enough space for growth of
the internal mirroring buffer due to MTU and speed changes. While vetoing
MTU changes would be merely confusing, port speed changes cannot be vetoed,
and such change would simply lead to issues in packet mirroring.

For these reasons, with these patches the internal mirroring buffer is
derived from maximum MTU and maximum speed achievable on the port.

Patches #1 and #2 introduce a new callback to determine the maximum speed a
given port can achieve.

With patches #3 and #4, the information about, respectively, maximum MTU
and maximum port speed, is kept in struct mlxsw_sp_port.

In patch #5, maximum MTU and maximum speed are used to determine the size
of the internal buffer. MTU update and speed update hooks are dropped,
because they are no longer necessary.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed Sep 14, 2020
2 parents 7952d7e + 532b49e commit 7b2d1b8
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 82 deletions.
43 changes: 29 additions & 14 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -590,21 +590,28 @@ static int mlxsw_sp_port_dev_addr_init(struct mlxsw_sp_port *mlxsw_sp_port)
return mlxsw_sp_port_dev_addr_set(mlxsw_sp_port, addr);
}

static int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu)
static int mlxsw_sp_port_max_mtu_get(struct mlxsw_sp_port *mlxsw_sp_port, int *p_max_mtu)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char pmtu_pl[MLXSW_REG_PMTU_LEN];
int max_mtu;
int err;

mtu += MLXSW_TXHDR_LEN + ETH_HLEN;
mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, 0);
err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl);
if (err)
return err;
max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl);

if (mtu > max_mtu)
*p_max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl);
return 0;
}

static int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char pmtu_pl[MLXSW_REG_PMTU_LEN];

mtu += MLXSW_TXHDR_LEN + ETH_HLEN;
if (mtu > mlxsw_sp_port->max_mtu)
return -EINVAL;

mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, mtu);
Expand Down Expand Up @@ -996,18 +1003,13 @@ static int mlxsw_sp_port_change_mtu(struct net_device *dev, int mtu)
err = mlxsw_sp_port_headroom_set(mlxsw_sp_port, mtu, pause_en);
if (err)
return err;
err = mlxsw_sp_span_port_mtu_update(mlxsw_sp_port, mtu);
if (err)
goto err_span_port_mtu_update;
err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, mtu);
if (err)
goto err_port_mtu_set;
dev->mtu = mtu;
return 0;

err_port_mtu_set:
mlxsw_sp_span_port_mtu_update(mlxsw_sp_port, dev->mtu);
err_span_port_mtu_update:
mlxsw_sp_port_headroom_set(mlxsw_sp_port, dev->mtu, pause_en);
return err;
}
Expand Down Expand Up @@ -1842,6 +1844,21 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
goto err_port_speed_by_width_set;
}

err = mlxsw_sp->port_type_speed_ops->ptys_max_speed(mlxsw_sp_port,
&mlxsw_sp_port->max_speed);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum speed\n",
mlxsw_sp_port->local_port);
goto err_max_speed_get;
}

err = mlxsw_sp_port_max_mtu_get(mlxsw_sp_port, &mlxsw_sp_port->max_mtu);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum MTU\n",
mlxsw_sp_port->local_port);
goto err_port_max_mtu_get;
}

err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, ETH_DATA_LEN);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set MTU\n",
Expand Down Expand Up @@ -1930,8 +1947,6 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,

INIT_DELAYED_WORK(&mlxsw_sp_port->ptp.shaper_dw,
mlxsw_sp->ptp_ops->shaper_work);
INIT_DELAYED_WORK(&mlxsw_sp_port->span.speed_update_dw,
mlxsw_sp_span_speed_update_work);

mlxsw_sp->ports[local_port] = mlxsw_sp_port;
err = register_netdev(dev);
Expand Down Expand Up @@ -1966,6 +1981,8 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
err_port_buffers_init:
err_port_admin_status_set:
err_port_mtu_set:
err_port_max_mtu_get:
err_max_speed_get:
err_port_speed_by_width_set:
err_port_system_port_mapping_set:
err_dev_addr_init:
Expand All @@ -1986,7 +2003,6 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];

cancel_delayed_work_sync(&mlxsw_sp_port->periodic_hw_stats.update_dw);
cancel_delayed_work_sync(&mlxsw_sp_port->span.speed_update_dw);
cancel_delayed_work_sync(&mlxsw_sp_port->ptp.shaper_dw);
mlxsw_sp_port_ptp_clear(mlxsw_sp_port);
mlxsw_core_port_clear(mlxsw_sp->core, local_port, mlxsw_sp);
Expand Down Expand Up @@ -2390,7 +2406,6 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
netdev_info(mlxsw_sp_port->dev, "link up\n");
netif_carrier_on(mlxsw_sp_port->dev);
mlxsw_core_schedule_dw(&mlxsw_sp_port->ptp.shaper_dw, 0);
mlxsw_core_schedule_dw(&mlxsw_sp_port->span.speed_update_dw, 0);
} else {
netdev_info(mlxsw_sp_port->dev, "link down\n");
netif_carrier_off(mlxsw_sp_port->dev);
Expand Down
6 changes: 3 additions & 3 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,8 @@ struct mlxsw_sp_port {
struct mlxsw_sp_ptp_port_stats stats;
} ptp;
u8 split_base_local_port;
struct {
struct delayed_work speed_update_dw;
} span;
int max_mtu;
u32 max_speed;
};

struct mlxsw_sp_port_type_speed_ops {
Expand All @@ -331,6 +330,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);
Expand Down
82 changes: 72 additions & 10 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -842,28 +842,47 @@ mlxsw_sp_port_connector_port(enum mlxsw_reg_ptys_connector_type connector_type)
}
}

static int mlxsw_sp_port_ptys_query(struct mlxsw_sp_port *mlxsw_sp_port,
u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
u32 *p_eth_proto_oper, u8 *p_connector_type)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
const struct mlxsw_sp_port_type_speed_ops *ops;
char ptys_pl[MLXSW_REG_PTYS_LEN];
int err;

ops = mlxsw_sp->port_type_speed_ops;

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);
if (err)
return err;

ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, p_eth_proto_cap, p_eth_proto_admin,
p_eth_proto_oper);
if (p_connector_type)
*p_connector_type = mlxsw_reg_ptys_connector_type_get(ptys_pl);
return 0;
}

static int mlxsw_sp_port_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
u32 eth_proto_cap, eth_proto_admin, eth_proto_oper;
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
const struct mlxsw_sp_port_type_speed_ops *ops;
char ptys_pl[MLXSW_REG_PTYS_LEN];
u8 connector_type;
bool autoneg;
int err;

ops = mlxsw_sp->port_type_speed_ops;

autoneg = mlxsw_sp_port->link.autoneg;
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);
err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, &eth_proto_cap, &eth_proto_admin,
&eth_proto_oper, &connector_type);
if (err)
return err;
ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, &eth_proto_cap,
&eth_proto_admin, &eth_proto_oper);

ops = mlxsw_sp->port_type_speed_ops;
autoneg = mlxsw_sp_port->link.autoneg;

mlxsw_sp_port_get_link_supported(mlxsw_sp, eth_proto_cap,
mlxsw_sp_port->mapping.width, cmd);
Expand All @@ -872,7 +891,6 @@ static int mlxsw_sp_port_get_link_ksettings(struct net_device *dev,
mlxsw_sp_port->mapping.width, cmd);

cmd->base.autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
connector_type = mlxsw_reg_ptys_connector_type_get(ptys_pl);
cmd->base.port = mlxsw_sp_port_connector_port(connector_type);
ops->from_ptys_speed_duplex(mlxsw_sp, netif_carrier_ok(dev),
eth_proto_oper, cmd);
Expand Down Expand Up @@ -1144,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)
Expand Down Expand Up @@ -1193,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,
Expand Down Expand Up @@ -1530,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)
Expand Down Expand Up @@ -1599,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,
Expand Down
59 changes: 4 additions & 55 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
Original file line number Diff line number Diff line change
Expand Up @@ -977,21 +977,14 @@ static u32 mlxsw_sp_span_buffsize_get(struct mlxsw_sp *mlxsw_sp, int mtu,
}

static int
mlxsw_sp_span_port_buffer_update(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu)
mlxsw_sp_span_port_buffer_enable(struct mlxsw_sp_port *mlxsw_sp_port)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char sbib_pl[MLXSW_REG_SBIB_LEN];
u32 buffsize;
u32 speed;
int err;

err = mlxsw_sp_port_speed_get(mlxsw_sp_port, &speed);
if (err)
return err;
if (speed == SPEED_UNKNOWN)
speed = 0;

buffsize = mlxsw_sp_span_buffsize_get(mlxsw_sp, speed, mtu);
buffsize = mlxsw_sp_span_buffsize_get(mlxsw_sp, mlxsw_sp_port->max_speed,
mlxsw_sp_port->max_mtu);
buffsize = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, buffsize);
mlxsw_reg_sbib_pack(sbib_pl, mlxsw_sp_port->local_port, buffsize);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
Expand Down Expand Up @@ -1021,48 +1014,6 @@ mlxsw_sp_span_analyzed_port_find(struct mlxsw_sp_span *span, u8 local_port,
return NULL;
}

int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu)
{
struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
int err = 0;

/* If port is egress mirrored, the shared buffer size should be
* updated according to the mtu value
*/
mutex_lock(&mlxsw_sp->span->analyzed_ports_lock);

if (mlxsw_sp_span_analyzed_port_find(mlxsw_sp->span, port->local_port,
false))
err = mlxsw_sp_span_port_buffer_update(port, mtu);

mutex_unlock(&mlxsw_sp->span->analyzed_ports_lock);

return err;
}

void mlxsw_sp_span_speed_update_work(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct mlxsw_sp_port *mlxsw_sp_port;
struct mlxsw_sp *mlxsw_sp;

mlxsw_sp_port = container_of(dwork, struct mlxsw_sp_port,
span.speed_update_dw);

/* If port is egress mirrored, the shared buffer size should be
* updated according to the speed value.
*/
mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
mutex_lock(&mlxsw_sp->span->analyzed_ports_lock);

if (mlxsw_sp_span_analyzed_port_find(mlxsw_sp->span,
mlxsw_sp_port->local_port, false))
mlxsw_sp_span_port_buffer_update(mlxsw_sp_port,
mlxsw_sp_port->dev->mtu);

mutex_unlock(&mlxsw_sp->span->analyzed_ports_lock);
}

static const struct mlxsw_sp_span_entry_ops *
mlxsw_sp_span_entry_ops(struct mlxsw_sp *mlxsw_sp,
const struct net_device *to_dev)
Expand Down Expand Up @@ -1180,9 +1131,7 @@ mlxsw_sp_span_analyzed_port_create(struct mlxsw_sp_span *span,
* does the mirroring.
*/
if (!ingress) {
u16 mtu = mlxsw_sp_port->dev->mtu;

err = mlxsw_sp_span_port_buffer_update(mlxsw_sp_port, mtu);
err = mlxsw_sp_span_port_buffer_enable(mlxsw_sp_port);
if (err)
goto err_buffer_update;
}
Expand Down

0 comments on commit 7b2d1b8

Please sign in to comment.