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: Petr Machata <petrm@nvidia.com> Signed-off-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
7df621a3ee
commit
48e4d00b1b
@ -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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user