Commit 48e4d00b authored by Petr Machata's avatar Petr Machata Committed by Jakub Kicinski

mlxsw: spectrum_qdisc: Offload root TBF as port shaper

The Spectrum ASIC allows configuration of maximum shaper on all levels of
the scheduling hierarchy: TCs, subgroups, groups and also ports. Currently,
TBF always configures a subgroup. But a user could reasonably express the
intent to configure port shaper by putting TBF to a root position, around
ETS / PRIO. Accept this usage and offload appropriately.
Signed-off-by: default avatarPetr Machata <petrm@nvidia.com>
Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 7df621a3
...@@ -271,6 +271,7 @@ mlxsw_sp_qdisc_destroy(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -271,6 +271,7 @@ mlxsw_sp_qdisc_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_qdisc_tree_validate { struct mlxsw_sp_qdisc_tree_validate {
bool forbid_ets; bool forbid_ets;
bool forbid_root_tbf;
bool forbid_tbf; bool forbid_tbf;
bool forbid_red; bool forbid_red;
}; };
...@@ -310,18 +311,26 @@ __mlxsw_sp_qdisc_tree_validate(struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, ...@@ -310,18 +311,26 @@ __mlxsw_sp_qdisc_tree_validate(struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
if (validate.forbid_red) if (validate.forbid_red)
return -EINVAL; return -EINVAL;
validate.forbid_red = true; validate.forbid_red = true;
validate.forbid_root_tbf = true;
validate.forbid_ets = true; validate.forbid_ets = true;
break; break;
case MLXSW_SP_QDISC_TBF: case MLXSW_SP_QDISC_TBF:
if (validate.forbid_tbf) if (validate.forbid_root_tbf) {
return -EINVAL; if (validate.forbid_tbf)
validate.forbid_tbf = true; return -EINVAL;
validate.forbid_ets = true; /* This is a TC TBF. */
validate.forbid_tbf = true;
validate.forbid_ets = true;
} else {
/* This is root TBF. */
validate.forbid_root_tbf = true;
}
break; break;
case MLXSW_SP_QDISC_PRIO: case MLXSW_SP_QDISC_PRIO:
case MLXSW_SP_QDISC_ETS: case MLXSW_SP_QDISC_ETS:
if (validate.forbid_ets) if (validate.forbid_ets)
return -EINVAL; return -EINVAL;
validate.forbid_root_tbf = true;
validate.forbid_ets = true; validate.forbid_ets = true;
break; break;
default: default:
...@@ -905,16 +914,34 @@ mlxsw_sp_setup_tc_qdisc_leaf_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -905,16 +914,34 @@ mlxsw_sp_setup_tc_qdisc_leaf_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_qdisc->stats_base.backlog = 0; mlxsw_sp_qdisc->stats_base.backlog = 0;
} }
static enum mlxsw_reg_qeec_hr
mlxsw_sp_qdisc_tbf_hr(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
{
if (mlxsw_sp_qdisc == &mlxsw_sp_port->qdisc->root_qdisc)
return MLXSW_REG_QEEC_HR_PORT;
/* Configure subgroup shaper, so that both UC and MC traffic is subject
* to shaping. That is unlike RED, however UC queue lengths are going to
* be different than MC ones due to different pool and quota
* configurations, so the configuration is not applicable. For shaper on
* the other hand, subjecting the overall stream to the configured
* shaper makes sense. Also note that that is what we do for
* ieee_setmaxrate().
*/
return MLXSW_REG_QEEC_HR_SUBGROUP;
}
static int static int
mlxsw_sp_qdisc_tbf_destroy(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_qdisc_tbf_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
{ {
enum mlxsw_reg_qeec_hr hr = mlxsw_sp_qdisc_tbf_hr(mlxsw_sp_port,
mlxsw_sp_qdisc);
int tclass_num = mlxsw_sp_qdisc_get_tclass_num(mlxsw_sp_port, int tclass_num = mlxsw_sp_qdisc_get_tclass_num(mlxsw_sp_port,
mlxsw_sp_qdisc); mlxsw_sp_qdisc);
return mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, return mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, hr, tclass_num, 0,
MLXSW_REG_QEEC_HR_SUBGROUP,
tclass_num, 0,
MLXSW_REG_QEEC_MAS_DIS, 0); MLXSW_REG_QEEC_MAS_DIS, 0);
} }
...@@ -996,6 +1023,8 @@ mlxsw_sp_qdisc_tbf_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, ...@@ -996,6 +1023,8 @@ mlxsw_sp_qdisc_tbf_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
void *params) void *params)
{ {
enum mlxsw_reg_qeec_hr hr = mlxsw_sp_qdisc_tbf_hr(mlxsw_sp_port,
mlxsw_sp_qdisc);
struct tc_tbf_qopt_offload_replace_params *p = params; struct tc_tbf_qopt_offload_replace_params *p = params;
u64 rate_kbps = mlxsw_sp_qdisc_tbf_rate_kbps(p); u64 rate_kbps = mlxsw_sp_qdisc_tbf_rate_kbps(p);
int tclass_num; int tclass_num;
...@@ -1016,17 +1045,7 @@ mlxsw_sp_qdisc_tbf_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, ...@@ -1016,17 +1045,7 @@ mlxsw_sp_qdisc_tbf_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
/* check_params above was supposed to reject this value. */ /* check_params above was supposed to reject this value. */
return -EINVAL; return -EINVAL;
/* Configure subgroup shaper, so that both UC and MC traffic is subject return mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, hr, tclass_num, 0,
* to shaping. That is unlike RED, however UC queue lengths are going to
* be different than MC ones due to different pool and quota
* configurations, so the configuration is not applicable. For shaper on
* the other hand, subjecting the overall stream to the configured
* shaper makes sense. Also note that that is what we do for
* ieee_setmaxrate().
*/
return mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
MLXSW_REG_QEEC_HR_SUBGROUP,
tclass_num, 0,
rate_kbps, burst_size); rate_kbps, burst_size);
} }
......
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