Commit 7917f52a authored by Petr Machata's avatar Petr Machata Committed by David S. Miller

mlxsw: spectrum_qdisc: Generalize PRIO offload to support ETS

Thanks to the similarity between PRIO and ETS it is possible to simply
reuse most of the code for offloading PRIO Qdisc. Extract the common
functionality into separate functions, making the current PRIO handlers
thin API adapters.

Extend the new functions to pass quanta for individual bands, which allows
configuring a subset of bands as WRR. Invoke mlxsw_sp_port_ets_set() as
appropriate to de/configure WRR-ness and weight of individual bands.
Signed-off-by: default avatarPetr Machata <petrm@mellanox.com>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Reviewed-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d35eb52b
...@@ -471,14 +471,16 @@ int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -471,14 +471,16 @@ int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port,
} }
static int static int
mlxsw_sp_qdisc_prio_destroy(struct mlxsw_sp_port *mlxsw_sp_port, __mlxsw_sp_qdisc_ets_destroy(struct mlxsw_sp_port *mlxsw_sp_port)
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
{ {
int i; int i;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i,
MLXSW_SP_PORT_DEFAULT_TCLASS); MLXSW_SP_PORT_DEFAULT_TCLASS);
mlxsw_sp_port_ets_set(mlxsw_sp_port,
MLXSW_REG_QEEC_HR_SUBGROUP,
i, 0, false, 0);
mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc_destroy(mlxsw_sp_port,
&mlxsw_sp_port->tclass_qdiscs[i]); &mlxsw_sp_port->tclass_qdiscs[i]);
mlxsw_sp_port->tclass_qdiscs[i].prio_bitmap = 0; mlxsw_sp_port->tclass_qdiscs[i].prio_bitmap = 0;
...@@ -488,36 +490,58 @@ mlxsw_sp_qdisc_prio_destroy(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -488,36 +490,58 @@ mlxsw_sp_qdisc_prio_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
} }
static int static int
mlxsw_sp_qdisc_prio_check_params(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_qdisc_prio_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
void *params)
{ {
struct tc_prio_qopt_offload_params *p = params; return __mlxsw_sp_qdisc_ets_destroy(mlxsw_sp_port);
}
if (p->bands > IEEE_8021QAZ_MAX_TCS) static int
__mlxsw_sp_qdisc_ets_check_params(unsigned int nbands)
{
if (nbands > IEEE_8021QAZ_MAX_TCS)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return 0; return 0;
} }
static int static int
mlxsw_sp_qdisc_prio_replace(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_qdisc_prio_check_params(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
void *params) void *params)
{ {
struct tc_prio_qopt_offload_params *p = params; struct tc_prio_qopt_offload_params *p = params;
return __mlxsw_sp_qdisc_ets_check_params(p->bands);
}
static int
__mlxsw_sp_qdisc_ets_replace(struct mlxsw_sp_port *mlxsw_sp_port,
unsigned int nbands,
const unsigned int *quanta,
const unsigned int *weights,
const u8 *priomap)
{
struct mlxsw_sp_qdisc *child_qdisc; struct mlxsw_sp_qdisc *child_qdisc;
int tclass, i, band, backlog; int tclass, i, band, backlog;
u8 old_priomap; u8 old_priomap;
int err; int err;
for (band = 0; band < p->bands; band++) { for (band = 0; band < nbands; band++) {
tclass = MLXSW_SP_PRIO_BAND_TO_TCLASS(band); tclass = MLXSW_SP_PRIO_BAND_TO_TCLASS(band);
child_qdisc = &mlxsw_sp_port->tclass_qdiscs[tclass]; child_qdisc = &mlxsw_sp_port->tclass_qdiscs[tclass];
old_priomap = child_qdisc->prio_bitmap; old_priomap = child_qdisc->prio_bitmap;
child_qdisc->prio_bitmap = 0; child_qdisc->prio_bitmap = 0;
err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
MLXSW_REG_QEEC_HR_SUBGROUP,
tclass, 0, !!quanta[band],
weights[band]);
if (err)
return err;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
if (p->priomap[i] == band) { if (priomap[i] == band) {
child_qdisc->prio_bitmap |= BIT(i); child_qdisc->prio_bitmap |= BIT(i);
if (BIT(i) & old_priomap) if (BIT(i) & old_priomap)
continue; continue;
...@@ -540,21 +564,46 @@ mlxsw_sp_qdisc_prio_replace(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -540,21 +564,46 @@ mlxsw_sp_qdisc_prio_replace(struct mlxsw_sp_port *mlxsw_sp_port,
child_qdisc = &mlxsw_sp_port->tclass_qdiscs[tclass]; child_qdisc = &mlxsw_sp_port->tclass_qdiscs[tclass];
child_qdisc->prio_bitmap = 0; child_qdisc->prio_bitmap = 0;
mlxsw_sp_qdisc_destroy(mlxsw_sp_port, child_qdisc); mlxsw_sp_qdisc_destroy(mlxsw_sp_port, child_qdisc);
mlxsw_sp_port_ets_set(mlxsw_sp_port,
MLXSW_REG_QEEC_HR_SUBGROUP,
tclass, 0, false, 0);
} }
return 0; return 0;
} }
static int
mlxsw_sp_qdisc_prio_replace(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
void *params)
{
struct tc_prio_qopt_offload_params *p = params;
unsigned int zeroes[TCQ_ETS_MAX_BANDS] = {0};
return __mlxsw_sp_qdisc_ets_replace(mlxsw_sp_port, p->bands,
zeroes, zeroes, p->priomap);
}
static void
__mlxsw_sp_qdisc_ets_unoffload(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
struct gnet_stats_queue *qstats)
{
u64 backlog;
backlog = mlxsw_sp_cells_bytes(mlxsw_sp_port->mlxsw_sp,
mlxsw_sp_qdisc->stats_base.backlog);
qstats->backlog -= backlog;
}
static void static void
mlxsw_sp_qdisc_prio_unoffload(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_qdisc_prio_unoffload(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
void *params) void *params)
{ {
struct tc_prio_qopt_offload_params *p = params; struct tc_prio_qopt_offload_params *p = params;
u64 backlog;
backlog = mlxsw_sp_cells_bytes(mlxsw_sp_port->mlxsw_sp, __mlxsw_sp_qdisc_ets_unoffload(mlxsw_sp_port, mlxsw_sp_qdisc,
mlxsw_sp_qdisc->stats_base.backlog); p->qstats);
p->qstats->backlog -= backlog;
} }
static int static int
...@@ -657,22 +706,22 @@ static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_prio = { ...@@ -657,22 +706,22 @@ static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_prio = {
* unoffload the child. * unoffload the child.
*/ */
static int static int
mlxsw_sp_qdisc_prio_graft(struct mlxsw_sp_port *mlxsw_sp_port, __mlxsw_sp_qdisc_ets_graft(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
struct tc_prio_qopt_offload_graft_params *p) u8 band, u32 child_handle)
{ {
int tclass_num = MLXSW_SP_PRIO_BAND_TO_TCLASS(p->band); int tclass_num = MLXSW_SP_PRIO_BAND_TO_TCLASS(band);
struct mlxsw_sp_qdisc *old_qdisc; struct mlxsw_sp_qdisc *old_qdisc;
if (p->band < IEEE_8021QAZ_MAX_TCS && if (band < IEEE_8021QAZ_MAX_TCS &&
mlxsw_sp_port->tclass_qdiscs[tclass_num].handle == p->child_handle) mlxsw_sp_port->tclass_qdiscs[tclass_num].handle == child_handle)
return 0; return 0;
/* See if the grafted qdisc is already offloaded on any tclass. If so, /* See if the grafted qdisc is already offloaded on any tclass. If so,
* unoffload it. * unoffload it.
*/ */
old_qdisc = mlxsw_sp_qdisc_find_by_handle(mlxsw_sp_port, old_qdisc = mlxsw_sp_qdisc_find_by_handle(mlxsw_sp_port,
p->child_handle); child_handle);
if (old_qdisc) if (old_qdisc)
mlxsw_sp_qdisc_destroy(mlxsw_sp_port, old_qdisc); mlxsw_sp_qdisc_destroy(mlxsw_sp_port, old_qdisc);
...@@ -681,6 +730,15 @@ mlxsw_sp_qdisc_prio_graft(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -681,6 +730,15 @@ mlxsw_sp_qdisc_prio_graft(struct mlxsw_sp_port *mlxsw_sp_port,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int
mlxsw_sp_qdisc_prio_graft(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
struct tc_prio_qopt_offload_graft_params *p)
{
return __mlxsw_sp_qdisc_ets_graft(mlxsw_sp_port, mlxsw_sp_qdisc,
p->band, p->child_handle);
}
int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port, int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
struct tc_prio_qopt_offload *p) struct tc_prio_qopt_offload *p)
{ {
......
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