Merge branch 'mlxsw-Support-dcbnl_setbuffer-dcbnl_getbuffer'
Ido Schimmel says: ==================== mlxsw: Support dcbnl_setbuffer, dcbnl_getbuffer Petr says: On Spectrum, port buffers, also called port headroom, is where packets are stored while they are parsed and the forwarding decision is being made. For lossless traffic flows, in case shared buffer admission is not allowed, headroom is also where to put the extra traffic received before the sent PAUSE takes effect. Linux supports two DCB interfaces related to the headroom: dcbnl_setbuffer for configuration, and dcbnl_getbuffer for inspection. This patch set implements them. With dcbnl_setbuffer in place, there will be two sources of authority over the ingress configuration: the DCB ETS hook, because ETS configuration is mirrored to ingress, and the DCB setbuffer hook. mlxsw is in a similar situation on the egress side, where there are two sources of the ETS configuration: the DCB ETS hook, and the TC qdisc hooks. This is a non-intuitive situation, because the way the ASIC ends up being configured depends not only on the actual configured bits, but also on the order in which they were configured. To prevent these issues on the ingress side, two configuration modes will exist: DCB mode and TC mode. DCB ETS will keep getting projected to ingress in the (default) DCB mode. When a qdisc is installed on a port, it will be switched to the TC mode, the ingress configuration will be done through the dcbnl_setbuffer callback. The reason is that the dcbnl_setbuffer hook is not standardized and supported by lldpad. Projecting DCB ETS configuration to ingress is a reasonable heuristic to configure ingress especially when PFC is in effect. In patch #1, the toggle between the DCB and TC modes of headroom configuration, described above, is introduced. Patch #2 implements dcbnl_getbuffer and dcbnl_setbuffer. dcbnl_getbuffer can be always used to determine the current port headroom configuration. dcbnl_setbuffer is only permitted in the TC mode. In patch #3, make the qdisc module toggle the headroom mode from DCB to TC and back, depending on whether there is an offloaded qdisc on the port. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
72d61d3009
@ -434,18 +434,29 @@ struct mlxsw_sp_hdroom_prio {
|
||||
u8 buf_idx;
|
||||
/* Value of buf_idx deduced from the DCB ETS configuration. */
|
||||
u8 ets_buf_idx;
|
||||
/* Value of buf_idx taken from the dcbnl_setbuffer configuration. */
|
||||
u8 set_buf_idx;
|
||||
bool lossy;
|
||||
};
|
||||
|
||||
struct mlxsw_sp_hdroom_buf {
|
||||
u32 thres_cells;
|
||||
u32 size_cells;
|
||||
/* Size requirement form dcbnl_setbuffer. */
|
||||
u32 set_size_cells;
|
||||
bool lossy;
|
||||
};
|
||||
|
||||
enum mlxsw_sp_hdroom_mode {
|
||||
MLXSW_SP_HDROOM_MODE_DCB,
|
||||
MLXSW_SP_HDROOM_MODE_TC,
|
||||
};
|
||||
|
||||
#define MLXSW_SP_PB_COUNT 10
|
||||
|
||||
struct mlxsw_sp_hdroom {
|
||||
enum mlxsw_sp_hdroom_mode mode;
|
||||
|
||||
struct {
|
||||
struct mlxsw_sp_hdroom_prio prio[IEEE_8021Q_MAX_PRIORITIES];
|
||||
} prios;
|
||||
|
@ -304,8 +304,16 @@ void mlxsw_sp_hdroom_prios_reset_buf_idx(struct mlxsw_sp_hdroom *hdroom)
|
||||
{
|
||||
int prio;
|
||||
|
||||
for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
|
||||
hdroom->prios.prio[prio].buf_idx = hdroom->prios.prio[prio].ets_buf_idx;
|
||||
for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) {
|
||||
switch (hdroom->mode) {
|
||||
case MLXSW_SP_HDROOM_MODE_DCB:
|
||||
hdroom->prios.prio[prio].buf_idx = hdroom->prios.prio[prio].ets_buf_idx;
|
||||
break;
|
||||
case MLXSW_SP_HDROOM_MODE_TC:
|
||||
hdroom->prios.prio[prio].buf_idx = hdroom->prios.prio[prio].set_buf_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mlxsw_sp_hdroom_bufs_reset_lossiness(struct mlxsw_sp_hdroom *hdroom)
|
||||
@ -411,7 +419,14 @@ void mlxsw_sp_hdroom_bufs_reset_sizes(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
delay_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, delay_cells);
|
||||
|
||||
buf->thres_cells = thres_cells;
|
||||
buf->size_cells = thres_cells + delay_cells;
|
||||
if (hdroom->mode == MLXSW_SP_HDROOM_MODE_DCB) {
|
||||
buf->size_cells = thres_cells + delay_cells;
|
||||
} else {
|
||||
/* Do not allow going below the minimum size, even if
|
||||
* the user requested it.
|
||||
*/
|
||||
buf->size_cells = max(buf->set_size_cells, buf->thres_cells);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -575,6 +590,7 @@ static int mlxsw_sp_port_headroom_init(struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
int prio;
|
||||
|
||||
hdroom.mtu = mlxsw_sp_port->dev->mtu;
|
||||
hdroom.mode = MLXSW_SP_HDROOM_MODE_DCB;
|
||||
for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
|
||||
hdroom.prios.prio[prio].lossy = true;
|
||||
|
||||
|
@ -592,6 +592,62 @@ err_port_pfc_set:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_dcbnl_getbuffer(struct net_device *dev, struct dcbnl_buffer *buf)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
|
||||
struct mlxsw_sp_hdroom *hdroom = mlxsw_sp_port->hdroom;
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
int prio;
|
||||
int i;
|
||||
|
||||
buf->total_size = 0;
|
||||
|
||||
BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT);
|
||||
for (i = 0; i < MLXSW_SP_PB_COUNT; i++) {
|
||||
u32 bytes = mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->bufs.buf[i].size_cells);
|
||||
|
||||
if (i < DCBX_MAX_BUFFERS)
|
||||
buf->buffer_size[i] = bytes;
|
||||
buf->total_size += bytes;
|
||||
}
|
||||
|
||||
buf->total_size += mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->int_buf.size_cells);
|
||||
|
||||
for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++)
|
||||
buf->prio2buffer[prio] = hdroom->prios.prio[prio].buf_idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_dcbnl_setbuffer(struct net_device *dev, struct dcbnl_buffer *buf)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
struct mlxsw_sp_hdroom hdroom;
|
||||
int prio;
|
||||
int i;
|
||||
|
||||
hdroom = *mlxsw_sp_port->hdroom;
|
||||
|
||||
if (hdroom.mode != MLXSW_SP_HDROOM_MODE_TC) {
|
||||
netdev_err(dev, "The use of dcbnl_setbuffer is only allowed if egress is configured using TC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++)
|
||||
hdroom.prios.prio[prio].set_buf_idx = buf->prio2buffer[prio];
|
||||
|
||||
BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT);
|
||||
for (i = 0; i < DCBX_MAX_BUFFERS; i++)
|
||||
hdroom.bufs.buf[i].set_size_cells = mlxsw_sp_bytes_cells(mlxsw_sp,
|
||||
buf->buffer_size[i]);
|
||||
|
||||
mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
|
||||
mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
|
||||
mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
|
||||
return mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
|
||||
}
|
||||
|
||||
static const struct dcbnl_rtnl_ops mlxsw_sp_dcbnl_ops = {
|
||||
.ieee_getets = mlxsw_sp_dcbnl_ieee_getets,
|
||||
.ieee_setets = mlxsw_sp_dcbnl_ieee_setets,
|
||||
@ -604,6 +660,9 @@ static const struct dcbnl_rtnl_ops mlxsw_sp_dcbnl_ops = {
|
||||
|
||||
.getdcbx = mlxsw_sp_dcbnl_getdcbx,
|
||||
.setdcbx = mlxsw_sp_dcbnl_setdcbx,
|
||||
|
||||
.dcbnl_getbuffer = mlxsw_sp_dcbnl_getbuffer,
|
||||
.dcbnl_setbuffer = mlxsw_sp_dcbnl_setbuffer,
|
||||
};
|
||||
|
||||
static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
|
@ -140,18 +140,31 @@ static int
|
||||
mlxsw_sp_qdisc_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
|
||||
{
|
||||
struct mlxsw_sp_qdisc *root_qdisc = &mlxsw_sp_port->qdisc->root_qdisc;
|
||||
int err_hdroom = 0;
|
||||
int err = 0;
|
||||
|
||||
if (!mlxsw_sp_qdisc)
|
||||
return 0;
|
||||
|
||||
if (root_qdisc == mlxsw_sp_qdisc) {
|
||||
struct mlxsw_sp_hdroom hdroom = *mlxsw_sp_port->hdroom;
|
||||
|
||||
hdroom.mode = MLXSW_SP_HDROOM_MODE_DCB;
|
||||
mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
|
||||
mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
|
||||
mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
|
||||
err_hdroom = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
|
||||
}
|
||||
|
||||
if (mlxsw_sp_qdisc->ops && mlxsw_sp_qdisc->ops->destroy)
|
||||
err = mlxsw_sp_qdisc->ops->destroy(mlxsw_sp_port,
|
||||
mlxsw_sp_qdisc);
|
||||
|
||||
mlxsw_sp_qdisc->handle = TC_H_UNSPEC;
|
||||
mlxsw_sp_qdisc->ops = NULL;
|
||||
return err;
|
||||
|
||||
return err_hdroom ?: err;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -159,6 +172,8 @@ mlxsw_sp_qdisc_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
struct mlxsw_sp_qdisc_ops *ops, void *params)
|
||||
{
|
||||
struct mlxsw_sp_qdisc *root_qdisc = &mlxsw_sp_port->qdisc->root_qdisc;
|
||||
struct mlxsw_sp_hdroom orig_hdroom;
|
||||
int err;
|
||||
|
||||
if (mlxsw_sp_qdisc->ops && mlxsw_sp_qdisc->ops->type != ops->type)
|
||||
@ -168,6 +183,21 @@ mlxsw_sp_qdisc_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
|
||||
* new one.
|
||||
*/
|
||||
mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
|
||||
|
||||
orig_hdroom = *mlxsw_sp_port->hdroom;
|
||||
if (root_qdisc == mlxsw_sp_qdisc) {
|
||||
struct mlxsw_sp_hdroom hdroom = orig_hdroom;
|
||||
|
||||
hdroom.mode = MLXSW_SP_HDROOM_MODE_TC;
|
||||
mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
|
||||
mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
|
||||
mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
|
||||
|
||||
err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
|
||||
if (err)
|
||||
goto err_hdroom_configure;
|
||||
}
|
||||
|
||||
err = ops->check_params(mlxsw_sp_port, mlxsw_sp_qdisc, params);
|
||||
if (err)
|
||||
goto err_bad_param;
|
||||
@ -191,6 +221,8 @@ mlxsw_sp_qdisc_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
|
||||
|
||||
err_bad_param:
|
||||
err_config:
|
||||
mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
|
||||
err_hdroom_configure:
|
||||
if (mlxsw_sp_qdisc->handle == handle && ops->unoffload)
|
||||
ops->unoffload(mlxsw_sp_port, mlxsw_sp_qdisc, params);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user