Commit 7ace2c36 authored by Petr Machata's avatar Petr Machata Committed by David S. Miller

mlxsw: spectrum: Move here the three-step headroom configuration from DCB

The ETS handler performs the headroom configuration in three steps: first
it resizes the buffers and adds any new ones. Then it redirects priorities
to the new buffers. And finally it sets the size of the now-unused buffers
to zero. This way no packet drops are introduced.

This sort of careful approach will also be useful for configuring port
buffer sizes and priority map by hand, through dcbnl_setbuffer. Therefore
move the code from the DCB handler to the generic headroom function.
Signed-off-by: default avatarPetr Machata <petrm@nvidia.com>
Reviewed-by: default avatarJiri Pirko <jiri@nvidia.com>
Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e9c97e0e
...@@ -718,6 +718,30 @@ static int mlxsw_sp_hdroom_configure_buffers(struct mlxsw_sp_port *mlxsw_sp_port ...@@ -718,6 +718,30 @@ static int mlxsw_sp_hdroom_configure_buffers(struct mlxsw_sp_port *mlxsw_sp_port
return 0; return 0;
} }
static int mlxsw_sp_hdroom_configure_priomap(struct mlxsw_sp_port *mlxsw_sp_port,
const struct mlxsw_sp_hdroom *hdroom, bool force)
{
char pptb_pl[MLXSW_REG_PPTB_LEN];
bool dirty;
int prio;
int err;
dirty = memcmp(&mlxsw_sp_port->hdroom->prios, &hdroom->prios, sizeof(hdroom->prios));
if (!dirty && !force)
return 0;
mlxsw_reg_pptb_pack(pptb_pl, mlxsw_sp_port->local_port);
for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
mlxsw_reg_pptb_prio_to_buff_pack(pptb_pl, prio, hdroom->prios.prio[prio].buf_idx);
err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pptb), pptb_pl);
if (err)
return err;
mlxsw_sp_port->hdroom->prios = hdroom->prios;
return 0;
}
static bool mlxsw_sp_hdroom_bufs_fit(struct mlxsw_sp *mlxsw_sp, static bool mlxsw_sp_hdroom_bufs_fit(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_hdroom *hdroom) const struct mlxsw_sp_hdroom *hdroom)
{ {
...@@ -735,17 +759,50 @@ static bool mlxsw_sp_hdroom_bufs_fit(struct mlxsw_sp *mlxsw_sp, ...@@ -735,17 +759,50 @@ static bool mlxsw_sp_hdroom_bufs_fit(struct mlxsw_sp *mlxsw_sp,
static int __mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port, static int __mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port,
const struct mlxsw_sp_hdroom *hdroom, bool force) const struct mlxsw_sp_hdroom *hdroom, bool force)
{ {
struct mlxsw_sp_hdroom orig_hdroom;
struct mlxsw_sp_hdroom tmp_hdroom;
int err; int err;
int i;
/* Port buffers need to be configured in three steps. First, all buffers
* with non-zero size are configured. Then, prio-to-buffer map is
* updated, allowing traffic to flow to the now non-zero buffers.
* Finally, zero-sized buffers are configured, because now no traffic
* should be directed to them anymore. This way, in a non-congested
* system, no packet drops are introduced by the reconfiguration.
*/
if (!mlxsw_sp_hdroom_bufs_fit(mlxsw_sp_port->mlxsw_sp, hdroom)) orig_hdroom = *mlxsw_sp_port->hdroom;
tmp_hdroom = orig_hdroom;
for (i = 0; i < MLXSW_SP_PB_COUNT; i++) {
if (hdroom->bufs.buf[i].size_cells)
tmp_hdroom.bufs.buf[i] = hdroom->bufs.buf[i];
}
if (!mlxsw_sp_hdroom_bufs_fit(mlxsw_sp_port->mlxsw_sp, &tmp_hdroom) ||
!mlxsw_sp_hdroom_bufs_fit(mlxsw_sp_port->mlxsw_sp, hdroom))
return -ENOBUFS; return -ENOBUFS;
err = mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, hdroom, false); err = mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, &tmp_hdroom, force);
if (err) if (err)
return err; return err;
err = mlxsw_sp_hdroom_configure_priomap(mlxsw_sp_port, hdroom, force);
if (err)
goto err_configure_priomap;
err = mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, hdroom, false);
if (err)
goto err_configure_buffers;
*mlxsw_sp_port->hdroom = *hdroom; *mlxsw_sp_port->hdroom = *hdroom;
return 0; return 0;
err_configure_buffers:
mlxsw_sp_hdroom_configure_priomap(mlxsw_sp_port, &tmp_hdroom, false);
err_configure_priomap:
mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, &orig_hdroom, false);
return err;
} }
int mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port, int mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port,
......
...@@ -64,85 +64,28 @@ static int mlxsw_sp_port_ets_validate(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -64,85 +64,28 @@ static int mlxsw_sp_port_ets_validate(struct mlxsw_sp_port *mlxsw_sp_port,
return 0; return 0;
} }
static int mlxsw_sp_hdroom_configure_priomap(struct mlxsw_sp_port *mlxsw_sp_port,
const struct mlxsw_sp_hdroom *hdroom, bool force)
{
char pptb_pl[MLXSW_REG_PPTB_LEN];
bool dirty;
int prio;
int err;
dirty = memcmp(&mlxsw_sp_port->hdroom->prios, &hdroom->prios, sizeof(hdroom->prios));
if (!dirty && !force)
return 0;
mlxsw_reg_pptb_pack(pptb_pl, mlxsw_sp_port->local_port);
for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
mlxsw_reg_pptb_prio_to_buff_pack(pptb_pl, prio, hdroom->prios.prio[prio].buf_idx);
err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pptb), pptb_pl);
if (err)
return err;
mlxsw_sp_port->hdroom->prios = hdroom->prios;
return 0;
}
static int mlxsw_sp_port_headroom_ets_set(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_port_headroom_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct ieee_ets *ets) struct ieee_ets *ets)
{ {
struct net_device *dev = mlxsw_sp_port->dev; struct net_device *dev = mlxsw_sp_port->dev;
struct mlxsw_sp_hdroom orig_hdroom;
struct mlxsw_sp_hdroom tmp_hdroom;
struct mlxsw_sp_hdroom hdroom; struct mlxsw_sp_hdroom hdroom;
int prio; int prio;
int err; int err;
int i;
orig_hdroom = *mlxsw_sp_port->hdroom; hdroom = *mlxsw_sp_port->hdroom;
hdroom = orig_hdroom;
for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
hdroom.prios.prio[prio].ets_buf_idx = ets->prio_tc[prio]; hdroom.prios.prio[prio].ets_buf_idx = ets->prio_tc[prio];
mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom); mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom); mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom); mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
/* Create the required PGs, but don't destroy existing ones, as err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
* traffic is still directed to them.
*/
tmp_hdroom = hdroom;
for (i = 0; i < DCBX_MAX_BUFFERS; i++) {
if (!tmp_hdroom.bufs.buf[i].size_cells)
tmp_hdroom.bufs.buf[i].size_cells =
mlxsw_sp_port->hdroom->bufs.buf[i].size_cells;
}
err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &tmp_hdroom);
if (err) { if (err) {
netdev_err(dev, "Failed to configure port's headroom\n"); netdev_err(dev, "Failed to configure port's headroom\n");
return err; return err;
} }
err = mlxsw_sp_hdroom_configure_priomap(mlxsw_sp_port, &hdroom, false);
if (err) {
netdev_err(dev, "Failed to set PG-priority mapping\n");
goto err_port_prio_pg_map;
}
err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
if (err) {
netdev_warn(dev, "Failed to remove unused PGs\n");
goto err_configure_buffers;
}
return 0; return 0;
err_configure_buffers:
mlxsw_sp_hdroom_configure_priomap(mlxsw_sp_port, &tmp_hdroom, false);
err_port_prio_pg_map:
mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
return err;
} }
static int __mlxsw_sp_dcbnl_ieee_setets(struct mlxsw_sp_port *mlxsw_sp_port, static int __mlxsw_sp_dcbnl_ieee_setets(struct mlxsw_sp_port *mlxsw_sp_port,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment