12d116e3eSDmytro Linkin // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
22d116e3eSDmytro Linkin /* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
32d116e3eSDmytro Linkin 
42d116e3eSDmytro Linkin #include "eswitch.h"
52d116e3eSDmytro Linkin #include "esw/qos.h"
6ad34f02fSDmytro Linkin #include "en/port.h"
73202ea65SDmytro Linkin #define CREATE_TRACE_POINTS
83202ea65SDmytro Linkin #include "diag/qos_tracepoint.h"
92d116e3eSDmytro Linkin 
102d116e3eSDmytro Linkin /* Minimum supported BW share value by the HW is 1 Mbit/sec */
112d116e3eSDmytro Linkin #define MLX5_MIN_BW_SHARE 1
122d116e3eSDmytro Linkin 
132d116e3eSDmytro Linkin #define MLX5_RATE_TO_BW_SHARE(rate, divider, limit) \
14ad34f02fSDmytro Linkin 	min_t(u32, max_t(u32, DIV_ROUND_UP(rate, divider), MLX5_MIN_BW_SHARE), limit)
152d116e3eSDmytro Linkin 
161ae258f8SDmytro Linkin struct mlx5_esw_rate_group {
171ae258f8SDmytro Linkin 	u32 tsar_ix;
181ae258f8SDmytro Linkin 	u32 max_rate;
191ae258f8SDmytro Linkin 	u32 min_rate;
201ae258f8SDmytro Linkin 	u32 bw_share;
21f47e04ebSDmytro Linkin 	struct list_head list;
221ae258f8SDmytro Linkin };
231ae258f8SDmytro Linkin 
esw_qos_tsar_config(struct mlx5_core_dev * dev,u32 * sched_ctx,u32 tsar_ix,u32 max_rate,u32 bw_share)24f47e04ebSDmytro Linkin static int esw_qos_tsar_config(struct mlx5_core_dev *dev, u32 *sched_ctx,
25f51471d1SMaor Dickman 			       u32 tsar_ix, u32 max_rate, u32 bw_share)
26f47e04ebSDmytro Linkin {
27f47e04ebSDmytro Linkin 	u32 bitmask = 0;
28f47e04ebSDmytro Linkin 
29f47e04ebSDmytro Linkin 	if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
30f47e04ebSDmytro Linkin 		return -EOPNOTSUPP;
31f47e04ebSDmytro Linkin 
32f47e04ebSDmytro Linkin 	MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
33f47e04ebSDmytro Linkin 	MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
34f47e04ebSDmytro Linkin 	bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
35f47e04ebSDmytro Linkin 	bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE;
36f47e04ebSDmytro Linkin 
37f47e04ebSDmytro Linkin 	return mlx5_modify_scheduling_element_cmd(dev,
38f47e04ebSDmytro Linkin 						  SCHEDULING_HIERARCHY_E_SWITCH,
39f47e04ebSDmytro Linkin 						  sched_ctx,
40f47e04ebSDmytro Linkin 						  tsar_ix,
41f47e04ebSDmytro Linkin 						  bitmask);
42f47e04ebSDmytro Linkin }
43f47e04ebSDmytro Linkin 
esw_qos_group_config(struct mlx5_eswitch * esw,struct mlx5_esw_rate_group * group,u32 max_rate,u32 bw_share,struct netlink_ext_ack * extack)44f47e04ebSDmytro Linkin static int esw_qos_group_config(struct mlx5_eswitch *esw, struct mlx5_esw_rate_group *group,
45f47e04ebSDmytro Linkin 				u32 max_rate, u32 bw_share, struct netlink_ext_ack *extack)
46f47e04ebSDmytro Linkin {
47f47e04ebSDmytro Linkin 	u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
48f47e04ebSDmytro Linkin 	struct mlx5_core_dev *dev = esw->dev;
49f47e04ebSDmytro Linkin 	int err;
50f47e04ebSDmytro Linkin 
51f47e04ebSDmytro Linkin 	err = esw_qos_tsar_config(dev, sched_ctx,
52f51471d1SMaor Dickman 				  group->tsar_ix,
53f47e04ebSDmytro Linkin 				  max_rate, bw_share);
54f47e04ebSDmytro Linkin 	if (err)
55f47e04ebSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "E-Switch modify group TSAR element failed");
56f47e04ebSDmytro Linkin 
573202ea65SDmytro Linkin 	trace_mlx5_esw_group_qos_config(dev, group, group->tsar_ix, bw_share, max_rate);
583202ea65SDmytro Linkin 
59f47e04ebSDmytro Linkin 	return err;
60f47e04ebSDmytro Linkin }
61f47e04ebSDmytro Linkin 
esw_qos_vport_config(struct mlx5_eswitch * esw,struct mlx5_vport * vport,u32 max_rate,u32 bw_share,struct netlink_ext_ack * extack)622d116e3eSDmytro Linkin static int esw_qos_vport_config(struct mlx5_eswitch *esw,
632d116e3eSDmytro Linkin 				struct mlx5_vport *vport,
64ad34f02fSDmytro Linkin 				u32 max_rate, u32 bw_share,
65ad34f02fSDmytro Linkin 				struct netlink_ext_ack *extack)
662d116e3eSDmytro Linkin {
672d116e3eSDmytro Linkin 	u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
682d116e3eSDmytro Linkin 	struct mlx5_core_dev *dev = esw->dev;
692d116e3eSDmytro Linkin 	int err;
702d116e3eSDmytro Linkin 
712d116e3eSDmytro Linkin 	if (!vport->qos.enabled)
722d116e3eSDmytro Linkin 		return -EIO;
732d116e3eSDmytro Linkin 
74f51471d1SMaor Dickman 	err = esw_qos_tsar_config(dev, sched_ctx, vport->qos.esw_tsar_ix,
75f47e04ebSDmytro Linkin 				  max_rate, bw_share);
762d116e3eSDmytro Linkin 	if (err) {
77f47e04ebSDmytro Linkin 		esw_warn(esw->dev,
78f47e04ebSDmytro Linkin 			 "E-Switch modify TSAR vport element failed (vport=%d,err=%d)\n",
792d116e3eSDmytro Linkin 			 vport->vport, err);
80ad34f02fSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "E-Switch modify TSAR vport element failed");
812d116e3eSDmytro Linkin 		return err;
822d116e3eSDmytro Linkin 	}
832d116e3eSDmytro Linkin 
843202ea65SDmytro Linkin 	trace_mlx5_esw_vport_qos_config(vport, bw_share, max_rate);
853202ea65SDmytro Linkin 
862d116e3eSDmytro Linkin 	return 0;
872d116e3eSDmytro Linkin }
882d116e3eSDmytro Linkin 
esw_qos_calculate_min_rate_divider(struct mlx5_eswitch * esw,struct mlx5_esw_rate_group * group,bool group_level)89f47e04ebSDmytro Linkin static u32 esw_qos_calculate_min_rate_divider(struct mlx5_eswitch *esw,
90f47e04ebSDmytro Linkin 					      struct mlx5_esw_rate_group *group,
91f47e04ebSDmytro Linkin 					      bool group_level)
922d116e3eSDmytro Linkin {
932d116e3eSDmytro Linkin 	u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
942d116e3eSDmytro Linkin 	struct mlx5_vport *evport;
952d116e3eSDmytro Linkin 	u32 max_guarantee = 0;
962d116e3eSDmytro Linkin 	unsigned long i;
972d116e3eSDmytro Linkin 
98f47e04ebSDmytro Linkin 	if (group_level) {
99f47e04ebSDmytro Linkin 		struct mlx5_esw_rate_group *group;
100f47e04ebSDmytro Linkin 
101f47e04ebSDmytro Linkin 		list_for_each_entry(group, &esw->qos.groups, list) {
102f47e04ebSDmytro Linkin 			if (group->min_rate < max_guarantee)
103f47e04ebSDmytro Linkin 				continue;
104f47e04ebSDmytro Linkin 			max_guarantee = group->min_rate;
105f47e04ebSDmytro Linkin 		}
106f47e04ebSDmytro Linkin 	} else {
1072d116e3eSDmytro Linkin 		mlx5_esw_for_each_vport(esw, i, evport) {
108f47e04ebSDmytro Linkin 			if (!evport->enabled || !evport->qos.enabled ||
1090fe132eaSDmytro Linkin 			    evport->qos.group != group || evport->qos.min_rate < max_guarantee)
1102d116e3eSDmytro Linkin 				continue;
1112d116e3eSDmytro Linkin 			max_guarantee = evport->qos.min_rate;
1122d116e3eSDmytro Linkin 		}
113f47e04ebSDmytro Linkin 	}
1142d116e3eSDmytro Linkin 
1152d116e3eSDmytro Linkin 	if (max_guarantee)
1162d116e3eSDmytro Linkin 		return max_t(u32, max_guarantee / fw_max_bw_share, 1);
1170fe132eaSDmytro Linkin 
1180fe132eaSDmytro Linkin 	/* If vports min rate divider is 0 but their group has bw_share configured, then
1190fe132eaSDmytro Linkin 	 * need to set bw_share for vports to minimal value.
1200fe132eaSDmytro Linkin 	 */
1215c4e8ae7SDmytro Linkin 	if (!group_level && !max_guarantee && group && group->bw_share)
1220fe132eaSDmytro Linkin 		return 1;
1232d116e3eSDmytro Linkin 	return 0;
1242d116e3eSDmytro Linkin }
1252d116e3eSDmytro Linkin 
esw_qos_calc_bw_share(u32 min_rate,u32 divider,u32 fw_max)126f47e04ebSDmytro Linkin static u32 esw_qos_calc_bw_share(u32 min_rate, u32 divider, u32 fw_max)
127f47e04ebSDmytro Linkin {
128f47e04ebSDmytro Linkin 	if (divider)
129f47e04ebSDmytro Linkin 		return MLX5_RATE_TO_BW_SHARE(min_rate, divider, fw_max);
130f47e04ebSDmytro Linkin 
131f47e04ebSDmytro Linkin 	return 0;
132f47e04ebSDmytro Linkin }
133f47e04ebSDmytro Linkin 
esw_qos_normalize_vports_min_rate(struct mlx5_eswitch * esw,struct mlx5_esw_rate_group * group,struct netlink_ext_ack * extack)134f47e04ebSDmytro Linkin static int esw_qos_normalize_vports_min_rate(struct mlx5_eswitch *esw,
135f47e04ebSDmytro Linkin 					     struct mlx5_esw_rate_group *group,
136f47e04ebSDmytro Linkin 					     struct netlink_ext_ack *extack)
1372d116e3eSDmytro Linkin {
1382d116e3eSDmytro Linkin 	u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
139f47e04ebSDmytro Linkin 	u32 divider = esw_qos_calculate_min_rate_divider(esw, group, false);
1402d116e3eSDmytro Linkin 	struct mlx5_vport *evport;
1412d116e3eSDmytro Linkin 	unsigned long i;
1422d116e3eSDmytro Linkin 	u32 bw_share;
1432d116e3eSDmytro Linkin 	int err;
1442d116e3eSDmytro Linkin 
1452d116e3eSDmytro Linkin 	mlx5_esw_for_each_vport(esw, i, evport) {
1460fe132eaSDmytro Linkin 		if (!evport->enabled || !evport->qos.enabled || evport->qos.group != group)
1472d116e3eSDmytro Linkin 			continue;
148f47e04ebSDmytro Linkin 		bw_share = esw_qos_calc_bw_share(evport->qos.min_rate, divider, fw_max_bw_share);
1492d116e3eSDmytro Linkin 
1502d116e3eSDmytro Linkin 		if (bw_share == evport->qos.bw_share)
1512d116e3eSDmytro Linkin 			continue;
1522d116e3eSDmytro Linkin 
153f47e04ebSDmytro Linkin 		err = esw_qos_vport_config(esw, evport, evport->qos.max_rate, bw_share, extack);
154f47e04ebSDmytro Linkin 		if (err)
1552d116e3eSDmytro Linkin 			return err;
156f47e04ebSDmytro Linkin 
157f47e04ebSDmytro Linkin 		evport->qos.bw_share = bw_share;
158f47e04ebSDmytro Linkin 	}
159f47e04ebSDmytro Linkin 
160f47e04ebSDmytro Linkin 	return 0;
161f47e04ebSDmytro Linkin }
162f47e04ebSDmytro Linkin 
esw_qos_normalize_groups_min_rate(struct mlx5_eswitch * esw,u32 divider,struct netlink_ext_ack * extack)163f47e04ebSDmytro Linkin static int esw_qos_normalize_groups_min_rate(struct mlx5_eswitch *esw, u32 divider,
164f47e04ebSDmytro Linkin 					     struct netlink_ext_ack *extack)
165f47e04ebSDmytro Linkin {
166f47e04ebSDmytro Linkin 	u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
167f47e04ebSDmytro Linkin 	struct mlx5_esw_rate_group *group;
168f47e04ebSDmytro Linkin 	u32 bw_share;
169f47e04ebSDmytro Linkin 	int err;
170f47e04ebSDmytro Linkin 
171f47e04ebSDmytro Linkin 	list_for_each_entry(group, &esw->qos.groups, list) {
172f47e04ebSDmytro Linkin 		bw_share = esw_qos_calc_bw_share(group->min_rate, divider, fw_max_bw_share);
173f47e04ebSDmytro Linkin 
174f47e04ebSDmytro Linkin 		if (bw_share == group->bw_share)
175f47e04ebSDmytro Linkin 			continue;
176f47e04ebSDmytro Linkin 
177f47e04ebSDmytro Linkin 		err = esw_qos_group_config(esw, group, group->max_rate, bw_share, extack);
178f47e04ebSDmytro Linkin 		if (err)
179f47e04ebSDmytro Linkin 			return err;
180f47e04ebSDmytro Linkin 
181f47e04ebSDmytro Linkin 		group->bw_share = bw_share;
1820fe132eaSDmytro Linkin 
1830fe132eaSDmytro Linkin 		/* All the group's vports need to be set with default bw_share
1840fe132eaSDmytro Linkin 		 * to enable them with QOS
1850fe132eaSDmytro Linkin 		 */
1860fe132eaSDmytro Linkin 		err = esw_qos_normalize_vports_min_rate(esw, group, extack);
1870fe132eaSDmytro Linkin 
1880fe132eaSDmytro Linkin 		if (err)
1890fe132eaSDmytro Linkin 			return err;
1902d116e3eSDmytro Linkin 	}
1912d116e3eSDmytro Linkin 
1922d116e3eSDmytro Linkin 	return 0;
1932d116e3eSDmytro Linkin }
1942d116e3eSDmytro Linkin 
esw_qos_set_vport_min_rate(struct mlx5_eswitch * esw,struct mlx5_vport * evport,u32 min_rate,struct netlink_ext_ack * extack)195d7df09f5SDmytro Linkin static int esw_qos_set_vport_min_rate(struct mlx5_eswitch *esw, struct mlx5_vport *evport,
196d7df09f5SDmytro Linkin 				      u32 min_rate, struct netlink_ext_ack *extack)
1972d116e3eSDmytro Linkin {
198ad34f02fSDmytro Linkin 	u32 fw_max_bw_share, previous_min_rate;
1992d116e3eSDmytro Linkin 	bool min_rate_supported;
2002d116e3eSDmytro Linkin 	int err;
2012d116e3eSDmytro Linkin 
202ad34f02fSDmytro Linkin 	lockdep_assert_held(&esw->state_lock);
2032d116e3eSDmytro Linkin 	fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
2042d116e3eSDmytro Linkin 	min_rate_supported = MLX5_CAP_QOS(esw->dev, esw_bw_share) &&
2052d116e3eSDmytro Linkin 				fw_max_bw_share >= MLX5_MIN_BW_SHARE;
206ad34f02fSDmytro Linkin 	if (min_rate && !min_rate_supported)
2072d116e3eSDmytro Linkin 		return -EOPNOTSUPP;
2082d116e3eSDmytro Linkin 	if (min_rate == evport->qos.min_rate)
209ad34f02fSDmytro Linkin 		return 0;
2102d116e3eSDmytro Linkin 
2112d116e3eSDmytro Linkin 	previous_min_rate = evport->qos.min_rate;
2122d116e3eSDmytro Linkin 	evport->qos.min_rate = min_rate;
2130fe132eaSDmytro Linkin 	err = esw_qos_normalize_vports_min_rate(esw, evport->qos.group, extack);
214ad34f02fSDmytro Linkin 	if (err)
2152d116e3eSDmytro Linkin 		evport->qos.min_rate = previous_min_rate;
216ad34f02fSDmytro Linkin 
2172d116e3eSDmytro Linkin 	return err;
2182d116e3eSDmytro Linkin }
2192d116e3eSDmytro Linkin 
esw_qos_set_vport_max_rate(struct mlx5_eswitch * esw,struct mlx5_vport * evport,u32 max_rate,struct netlink_ext_ack * extack)220d7df09f5SDmytro Linkin static int esw_qos_set_vport_max_rate(struct mlx5_eswitch *esw, struct mlx5_vport *evport,
221d7df09f5SDmytro Linkin 				      u32 max_rate, struct netlink_ext_ack *extack)
222ad34f02fSDmytro Linkin {
2230fe132eaSDmytro Linkin 	u32 act_max_rate = max_rate;
224ad34f02fSDmytro Linkin 	bool max_rate_supported;
225ad34f02fSDmytro Linkin 	int err;
226ad34f02fSDmytro Linkin 
227ad34f02fSDmytro Linkin 	lockdep_assert_held(&esw->state_lock);
228ad34f02fSDmytro Linkin 	max_rate_supported = MLX5_CAP_QOS(esw->dev, esw_rate_limit);
229ad34f02fSDmytro Linkin 
230ad34f02fSDmytro Linkin 	if (max_rate && !max_rate_supported)
231ad34f02fSDmytro Linkin 		return -EOPNOTSUPP;
2322d116e3eSDmytro Linkin 	if (max_rate == evport->qos.max_rate)
2332d116e3eSDmytro Linkin 		return 0;
2342d116e3eSDmytro Linkin 
2350fe132eaSDmytro Linkin 	/* If parent group has rate limit need to set to group
2360fe132eaSDmytro Linkin 	 * value when new max rate is 0.
2370fe132eaSDmytro Linkin 	 */
2380fe132eaSDmytro Linkin 	if (evport->qos.group && !max_rate)
2390fe132eaSDmytro Linkin 		act_max_rate = evport->qos.group->max_rate;
2400fe132eaSDmytro Linkin 
2410fe132eaSDmytro Linkin 	err = esw_qos_vport_config(esw, evport, act_max_rate, evport->qos.bw_share, extack);
242f47e04ebSDmytro Linkin 
2432d116e3eSDmytro Linkin 	if (!err)
2442d116e3eSDmytro Linkin 		evport->qos.max_rate = max_rate;
2452d116e3eSDmytro Linkin 
2462d116e3eSDmytro Linkin 	return err;
2472d116e3eSDmytro Linkin }
2482d116e3eSDmytro Linkin 
esw_qos_set_group_min_rate(struct mlx5_eswitch * esw,struct mlx5_esw_rate_group * group,u32 min_rate,struct netlink_ext_ack * extack)249f47e04ebSDmytro Linkin static int esw_qos_set_group_min_rate(struct mlx5_eswitch *esw, struct mlx5_esw_rate_group *group,
250f47e04ebSDmytro Linkin 				      u32 min_rate, struct netlink_ext_ack *extack)
251f47e04ebSDmytro Linkin {
252f47e04ebSDmytro Linkin 	u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
253f47e04ebSDmytro Linkin 	struct mlx5_core_dev *dev = esw->dev;
254f47e04ebSDmytro Linkin 	u32 previous_min_rate, divider;
255f47e04ebSDmytro Linkin 	int err;
256f47e04ebSDmytro Linkin 
257f47e04ebSDmytro Linkin 	if (!(MLX5_CAP_QOS(dev, esw_bw_share) && fw_max_bw_share >= MLX5_MIN_BW_SHARE))
258f47e04ebSDmytro Linkin 		return -EOPNOTSUPP;
259f47e04ebSDmytro Linkin 
260f47e04ebSDmytro Linkin 	if (min_rate == group->min_rate)
261f47e04ebSDmytro Linkin 		return 0;
262f47e04ebSDmytro Linkin 
263f47e04ebSDmytro Linkin 	previous_min_rate = group->min_rate;
264f47e04ebSDmytro Linkin 	group->min_rate = min_rate;
265f47e04ebSDmytro Linkin 	divider = esw_qos_calculate_min_rate_divider(esw, group, true);
266f47e04ebSDmytro Linkin 	err = esw_qos_normalize_groups_min_rate(esw, divider, extack);
267f47e04ebSDmytro Linkin 	if (err) {
268f47e04ebSDmytro Linkin 		group->min_rate = previous_min_rate;
269f47e04ebSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "E-Switch group min rate setting failed");
270f47e04ebSDmytro Linkin 
271f47e04ebSDmytro Linkin 		/* Attempt restoring previous configuration */
272f47e04ebSDmytro Linkin 		divider = esw_qos_calculate_min_rate_divider(esw, group, true);
273f47e04ebSDmytro Linkin 		if (esw_qos_normalize_groups_min_rate(esw, divider, extack))
274f47e04ebSDmytro Linkin 			NL_SET_ERR_MSG_MOD(extack, "E-Switch BW share restore failed");
275f47e04ebSDmytro Linkin 	}
276f47e04ebSDmytro Linkin 
277f47e04ebSDmytro Linkin 	return err;
278f47e04ebSDmytro Linkin }
279f47e04ebSDmytro Linkin 
esw_qos_set_group_max_rate(struct mlx5_eswitch * esw,struct mlx5_esw_rate_group * group,u32 max_rate,struct netlink_ext_ack * extack)280f47e04ebSDmytro Linkin static int esw_qos_set_group_max_rate(struct mlx5_eswitch *esw,
281f47e04ebSDmytro Linkin 				      struct mlx5_esw_rate_group *group,
282f47e04ebSDmytro Linkin 				      u32 max_rate, struct netlink_ext_ack *extack)
283f47e04ebSDmytro Linkin {
2840fe132eaSDmytro Linkin 	struct mlx5_vport *vport;
2850fe132eaSDmytro Linkin 	unsigned long i;
286f47e04ebSDmytro Linkin 	int err;
287f47e04ebSDmytro Linkin 
288f47e04ebSDmytro Linkin 	if (group->max_rate == max_rate)
289f47e04ebSDmytro Linkin 		return 0;
290f47e04ebSDmytro Linkin 
291f47e04ebSDmytro Linkin 	err = esw_qos_group_config(esw, group, max_rate, group->bw_share, extack);
292f47e04ebSDmytro Linkin 	if (err)
293f47e04ebSDmytro Linkin 		return err;
294f47e04ebSDmytro Linkin 
295f47e04ebSDmytro Linkin 	group->max_rate = max_rate;
296f47e04ebSDmytro Linkin 
2970fe132eaSDmytro Linkin 	/* Any unlimited vports in the group should be set
2980fe132eaSDmytro Linkin 	 * with the value of the group.
2990fe132eaSDmytro Linkin 	 */
3000fe132eaSDmytro Linkin 	mlx5_esw_for_each_vport(esw, i, vport) {
3010fe132eaSDmytro Linkin 		if (!vport->enabled || !vport->qos.enabled ||
3020fe132eaSDmytro Linkin 		    vport->qos.group != group || vport->qos.max_rate)
3030fe132eaSDmytro Linkin 			continue;
3040fe132eaSDmytro Linkin 
3050fe132eaSDmytro Linkin 		err = esw_qos_vport_config(esw, vport, max_rate, vport->qos.bw_share, extack);
3060fe132eaSDmytro Linkin 		if (err)
3070fe132eaSDmytro Linkin 			NL_SET_ERR_MSG_MOD(extack,
3080fe132eaSDmytro Linkin 					   "E-Switch vport implicit rate limit setting failed");
3090fe132eaSDmytro Linkin 	}
3100fe132eaSDmytro Linkin 
311f47e04ebSDmytro Linkin 	return err;
312f47e04ebSDmytro Linkin }
313f47e04ebSDmytro Linkin 
esw_qos_vport_create_sched_element(struct mlx5_eswitch * esw,struct mlx5_vport * vport,u32 max_rate,u32 bw_share)3140fe132eaSDmytro Linkin static int esw_qos_vport_create_sched_element(struct mlx5_eswitch *esw,
3150fe132eaSDmytro Linkin 					      struct mlx5_vport *vport,
3160fe132eaSDmytro Linkin 					      u32 max_rate, u32 bw_share)
3170fe132eaSDmytro Linkin {
3180fe132eaSDmytro Linkin 	u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
3190fe132eaSDmytro Linkin 	struct mlx5_esw_rate_group *group = vport->qos.group;
3200fe132eaSDmytro Linkin 	struct mlx5_core_dev *dev = esw->dev;
3210fe132eaSDmytro Linkin 	u32 parent_tsar_ix;
3220fe132eaSDmytro Linkin 	void *vport_elem;
3230fe132eaSDmytro Linkin 	int err;
3240fe132eaSDmytro Linkin 
3250fe132eaSDmytro Linkin 	parent_tsar_ix = group ? group->tsar_ix : esw->qos.root_tsar_ix;
3260fe132eaSDmytro Linkin 	MLX5_SET(scheduling_context, sched_ctx, element_type,
3270fe132eaSDmytro Linkin 		 SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT);
3280fe132eaSDmytro Linkin 	vport_elem = MLX5_ADDR_OF(scheduling_context, sched_ctx, element_attributes);
3290fe132eaSDmytro Linkin 	MLX5_SET(vport_element, vport_elem, vport_number, vport->vport);
3300fe132eaSDmytro Linkin 	MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_tsar_ix);
3310fe132eaSDmytro Linkin 	MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
3320fe132eaSDmytro Linkin 	MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
3330fe132eaSDmytro Linkin 
3340fe132eaSDmytro Linkin 	err = mlx5_create_scheduling_element_cmd(dev,
3350fe132eaSDmytro Linkin 						 SCHEDULING_HIERARCHY_E_SWITCH,
3360fe132eaSDmytro Linkin 						 sched_ctx,
3370fe132eaSDmytro Linkin 						 &vport->qos.esw_tsar_ix);
3380fe132eaSDmytro Linkin 	if (err) {
3390fe132eaSDmytro Linkin 		esw_warn(esw->dev, "E-Switch create TSAR vport element failed (vport=%d,err=%d)\n",
3400fe132eaSDmytro Linkin 			 vport->vport, err);
3410fe132eaSDmytro Linkin 		return err;
3420fe132eaSDmytro Linkin 	}
3430fe132eaSDmytro Linkin 
3440fe132eaSDmytro Linkin 	return 0;
3450fe132eaSDmytro Linkin }
3460fe132eaSDmytro Linkin 
esw_qos_update_group_scheduling_element(struct mlx5_eswitch * esw,struct mlx5_vport * vport,struct mlx5_esw_rate_group * curr_group,struct mlx5_esw_rate_group * new_group,struct netlink_ext_ack * extack)3470fe132eaSDmytro Linkin static int esw_qos_update_group_scheduling_element(struct mlx5_eswitch *esw,
3480fe132eaSDmytro Linkin 						   struct mlx5_vport *vport,
3490fe132eaSDmytro Linkin 						   struct mlx5_esw_rate_group *curr_group,
3500fe132eaSDmytro Linkin 						   struct mlx5_esw_rate_group *new_group,
3510fe132eaSDmytro Linkin 						   struct netlink_ext_ack *extack)
3520fe132eaSDmytro Linkin {
3530fe132eaSDmytro Linkin 	u32 max_rate;
3540fe132eaSDmytro Linkin 	int err;
3550fe132eaSDmytro Linkin 
3560fe132eaSDmytro Linkin 	err = mlx5_destroy_scheduling_element_cmd(esw->dev,
3570fe132eaSDmytro Linkin 						  SCHEDULING_HIERARCHY_E_SWITCH,
3580fe132eaSDmytro Linkin 						  vport->qos.esw_tsar_ix);
3590fe132eaSDmytro Linkin 	if (err) {
3600fe132eaSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR vport element failed");
3610fe132eaSDmytro Linkin 		return err;
3620fe132eaSDmytro Linkin 	}
3630fe132eaSDmytro Linkin 
3640fe132eaSDmytro Linkin 	vport->qos.group = new_group;
3650fe132eaSDmytro Linkin 	max_rate = vport->qos.max_rate ? vport->qos.max_rate : new_group->max_rate;
3660fe132eaSDmytro Linkin 
3670fe132eaSDmytro Linkin 	/* If vport is unlimited, we set the group's value.
3680fe132eaSDmytro Linkin 	 * Therefore, if the group is limited it will apply to
3690fe132eaSDmytro Linkin 	 * the vport as well and if not, vport will remain unlimited.
3700fe132eaSDmytro Linkin 	 */
3710fe132eaSDmytro Linkin 	err = esw_qos_vport_create_sched_element(esw, vport, max_rate, vport->qos.bw_share);
3720fe132eaSDmytro Linkin 	if (err) {
3730fe132eaSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "E-Switch vport group set failed.");
3740fe132eaSDmytro Linkin 		goto err_sched;
3750fe132eaSDmytro Linkin 	}
3760fe132eaSDmytro Linkin 
3770fe132eaSDmytro Linkin 	return 0;
3780fe132eaSDmytro Linkin 
3790fe132eaSDmytro Linkin err_sched:
3800fe132eaSDmytro Linkin 	vport->qos.group = curr_group;
3810fe132eaSDmytro Linkin 	max_rate = vport->qos.max_rate ? vport->qos.max_rate : curr_group->max_rate;
3820fe132eaSDmytro Linkin 	if (esw_qos_vport_create_sched_element(esw, vport, max_rate, vport->qos.bw_share))
3830fe132eaSDmytro Linkin 		esw_warn(esw->dev, "E-Switch vport group restore failed (vport=%d)\n",
3840fe132eaSDmytro Linkin 			 vport->vport);
3850fe132eaSDmytro Linkin 
3860fe132eaSDmytro Linkin 	return err;
3870fe132eaSDmytro Linkin }
3880fe132eaSDmytro Linkin 
esw_qos_vport_update_group(struct mlx5_eswitch * esw,struct mlx5_vport * vport,struct mlx5_esw_rate_group * group,struct netlink_ext_ack * extack)3890fe132eaSDmytro Linkin static int esw_qos_vport_update_group(struct mlx5_eswitch *esw,
3900fe132eaSDmytro Linkin 				      struct mlx5_vport *vport,
3910fe132eaSDmytro Linkin 				      struct mlx5_esw_rate_group *group,
3920fe132eaSDmytro Linkin 				      struct netlink_ext_ack *extack)
3930fe132eaSDmytro Linkin {
3940fe132eaSDmytro Linkin 	struct mlx5_esw_rate_group *new_group, *curr_group;
3950fe132eaSDmytro Linkin 	int err;
3960fe132eaSDmytro Linkin 
3970fe132eaSDmytro Linkin 	if (!vport->enabled)
3980fe132eaSDmytro Linkin 		return -EINVAL;
3990fe132eaSDmytro Linkin 
4000fe132eaSDmytro Linkin 	curr_group = vport->qos.group;
4010fe132eaSDmytro Linkin 	new_group = group ?: esw->qos.group0;
4020fe132eaSDmytro Linkin 	if (curr_group == new_group)
4030fe132eaSDmytro Linkin 		return 0;
4040fe132eaSDmytro Linkin 
4050fe132eaSDmytro Linkin 	err = esw_qos_update_group_scheduling_element(esw, vport, curr_group, new_group, extack);
4060fe132eaSDmytro Linkin 	if (err)
4070fe132eaSDmytro Linkin 		return err;
4080fe132eaSDmytro Linkin 
4090fe132eaSDmytro Linkin 	/* Recalculate bw share weights of old and new groups */
4101e59b32eSDmytro Linkin 	if (vport->qos.bw_share || new_group->bw_share) {
4110fe132eaSDmytro Linkin 		esw_qos_normalize_vports_min_rate(esw, curr_group, extack);
4120fe132eaSDmytro Linkin 		esw_qos_normalize_vports_min_rate(esw, new_group, extack);
4130fe132eaSDmytro Linkin 	}
4140fe132eaSDmytro Linkin 
4150fe132eaSDmytro Linkin 	return 0;
4160fe132eaSDmytro Linkin }
4170fe132eaSDmytro Linkin 
4181ae258f8SDmytro Linkin static struct mlx5_esw_rate_group *
__esw_qos_create_rate_group(struct mlx5_eswitch * esw,struct netlink_ext_ack * extack)41985c5f7c9SDmytro Linkin __esw_qos_create_rate_group(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack)
4201ae258f8SDmytro Linkin {
4211ae258f8SDmytro Linkin 	u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
4221ae258f8SDmytro Linkin 	struct mlx5_esw_rate_group *group;
423f47e04ebSDmytro Linkin 	u32 divider;
4241ae258f8SDmytro Linkin 	int err;
4251ae258f8SDmytro Linkin 
4261ae258f8SDmytro Linkin 	group = kzalloc(sizeof(*group), GFP_KERNEL);
4271ae258f8SDmytro Linkin 	if (!group)
4281ae258f8SDmytro Linkin 		return ERR_PTR(-ENOMEM);
4291ae258f8SDmytro Linkin 
4301ae258f8SDmytro Linkin 	MLX5_SET(scheduling_context, tsar_ctx, parent_element_id,
4311ae258f8SDmytro Linkin 		 esw->qos.root_tsar_ix);
4321ae258f8SDmytro Linkin 	err = mlx5_create_scheduling_element_cmd(esw->dev,
4331ae258f8SDmytro Linkin 						 SCHEDULING_HIERARCHY_E_SWITCH,
4341ae258f8SDmytro Linkin 						 tsar_ctx,
4351ae258f8SDmytro Linkin 						 &group->tsar_ix);
4361ae258f8SDmytro Linkin 	if (err) {
4371ae258f8SDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "E-Switch create TSAR for group failed");
4381ae258f8SDmytro Linkin 		goto err_sched_elem;
4391ae258f8SDmytro Linkin 	}
4401ae258f8SDmytro Linkin 
441f47e04ebSDmytro Linkin 	list_add_tail(&group->list, &esw->qos.groups);
442f47e04ebSDmytro Linkin 
443f47e04ebSDmytro Linkin 	divider = esw_qos_calculate_min_rate_divider(esw, group, true);
444f47e04ebSDmytro Linkin 	if (divider) {
445f47e04ebSDmytro Linkin 		err = esw_qos_normalize_groups_min_rate(esw, divider, extack);
446f47e04ebSDmytro Linkin 		if (err) {
447f47e04ebSDmytro Linkin 			NL_SET_ERR_MSG_MOD(extack, "E-Switch groups normalization failed");
448f47e04ebSDmytro Linkin 			goto err_min_rate;
449f47e04ebSDmytro Linkin 		}
450f47e04ebSDmytro Linkin 	}
4513202ea65SDmytro Linkin 	trace_mlx5_esw_group_qos_create(esw->dev, group, group->tsar_ix);
452f47e04ebSDmytro Linkin 
4531ae258f8SDmytro Linkin 	return group;
4541ae258f8SDmytro Linkin 
455f47e04ebSDmytro Linkin err_min_rate:
456f47e04ebSDmytro Linkin 	list_del(&group->list);
457a6f74333SDmytro Linkin 	if (mlx5_destroy_scheduling_element_cmd(esw->dev,
458f47e04ebSDmytro Linkin 						SCHEDULING_HIERARCHY_E_SWITCH,
459a6f74333SDmytro Linkin 						group->tsar_ix))
460f47e04ebSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR for group failed");
4611ae258f8SDmytro Linkin err_sched_elem:
4621ae258f8SDmytro Linkin 	kfree(group);
4631ae258f8SDmytro Linkin 	return ERR_PTR(err);
4641ae258f8SDmytro Linkin }
4651ae258f8SDmytro Linkin 
46685c5f7c9SDmytro Linkin static int esw_qos_get(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack);
46785c5f7c9SDmytro Linkin static void esw_qos_put(struct mlx5_eswitch *esw);
46885c5f7c9SDmytro Linkin 
46985c5f7c9SDmytro Linkin static struct mlx5_esw_rate_group *
esw_qos_create_rate_group(struct mlx5_eswitch * esw,struct netlink_ext_ack * extack)47085c5f7c9SDmytro Linkin esw_qos_create_rate_group(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack)
47185c5f7c9SDmytro Linkin {
47285c5f7c9SDmytro Linkin 	struct mlx5_esw_rate_group *group;
47385c5f7c9SDmytro Linkin 	int err;
47485c5f7c9SDmytro Linkin 
47585c5f7c9SDmytro Linkin 	if (!MLX5_CAP_QOS(esw->dev, log_esw_max_sched_depth))
47685c5f7c9SDmytro Linkin 		return ERR_PTR(-EOPNOTSUPP);
47785c5f7c9SDmytro Linkin 
47885c5f7c9SDmytro Linkin 	err = esw_qos_get(esw, extack);
47985c5f7c9SDmytro Linkin 	if (err)
48085c5f7c9SDmytro Linkin 		return ERR_PTR(err);
48185c5f7c9SDmytro Linkin 
48285c5f7c9SDmytro Linkin 	group = __esw_qos_create_rate_group(esw, extack);
48385c5f7c9SDmytro Linkin 	if (IS_ERR(group))
48485c5f7c9SDmytro Linkin 		esw_qos_put(esw);
48585c5f7c9SDmytro Linkin 
48685c5f7c9SDmytro Linkin 	return group;
48785c5f7c9SDmytro Linkin }
48885c5f7c9SDmytro Linkin 
__esw_qos_destroy_rate_group(struct mlx5_eswitch * esw,struct mlx5_esw_rate_group * group,struct netlink_ext_ack * extack)48985c5f7c9SDmytro Linkin static int __esw_qos_destroy_rate_group(struct mlx5_eswitch *esw,
4901ae258f8SDmytro Linkin 					struct mlx5_esw_rate_group *group,
4911ae258f8SDmytro Linkin 					struct netlink_ext_ack *extack)
4921ae258f8SDmytro Linkin {
493f47e04ebSDmytro Linkin 	u32 divider;
4941ae258f8SDmytro Linkin 	int err;
4951ae258f8SDmytro Linkin 
496f47e04ebSDmytro Linkin 	list_del(&group->list);
497f47e04ebSDmytro Linkin 
498f47e04ebSDmytro Linkin 	divider = esw_qos_calculate_min_rate_divider(esw, NULL, true);
499f47e04ebSDmytro Linkin 	err = esw_qos_normalize_groups_min_rate(esw, divider, extack);
500f47e04ebSDmytro Linkin 	if (err)
501f47e04ebSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "E-Switch groups' normalization failed");
502f47e04ebSDmytro Linkin 
5031ae258f8SDmytro Linkin 	err = mlx5_destroy_scheduling_element_cmd(esw->dev,
5041ae258f8SDmytro Linkin 						  SCHEDULING_HIERARCHY_E_SWITCH,
5051ae258f8SDmytro Linkin 						  group->tsar_ix);
5061ae258f8SDmytro Linkin 	if (err)
5071ae258f8SDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR_ID failed");
5081ae258f8SDmytro Linkin 
5093202ea65SDmytro Linkin 	trace_mlx5_esw_group_qos_destroy(esw->dev, group, group->tsar_ix);
51085c5f7c9SDmytro Linkin 
5111ae258f8SDmytro Linkin 	kfree(group);
51285c5f7c9SDmytro Linkin 
51385c5f7c9SDmytro Linkin 	return err;
51485c5f7c9SDmytro Linkin }
51585c5f7c9SDmytro Linkin 
esw_qos_destroy_rate_group(struct mlx5_eswitch * esw,struct mlx5_esw_rate_group * group,struct netlink_ext_ack * extack)51685c5f7c9SDmytro Linkin static int esw_qos_destroy_rate_group(struct mlx5_eswitch *esw,
51785c5f7c9SDmytro Linkin 				      struct mlx5_esw_rate_group *group,
51885c5f7c9SDmytro Linkin 				      struct netlink_ext_ack *extack)
51985c5f7c9SDmytro Linkin {
52085c5f7c9SDmytro Linkin 	int err;
52185c5f7c9SDmytro Linkin 
52285c5f7c9SDmytro Linkin 	err = __esw_qos_destroy_rate_group(esw, group, extack);
52385c5f7c9SDmytro Linkin 	esw_qos_put(esw);
52485c5f7c9SDmytro Linkin 
5251ae258f8SDmytro Linkin 	return err;
5261ae258f8SDmytro Linkin }
5271ae258f8SDmytro Linkin 
esw_qos_element_type_supported(struct mlx5_core_dev * dev,int type)5282d116e3eSDmytro Linkin static bool esw_qos_element_type_supported(struct mlx5_core_dev *dev, int type)
5292d116e3eSDmytro Linkin {
5302d116e3eSDmytro Linkin 	switch (type) {
5312d116e3eSDmytro Linkin 	case SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR:
5322d116e3eSDmytro Linkin 		return MLX5_CAP_QOS(dev, esw_element_type) &
5332d116e3eSDmytro Linkin 		       ELEMENT_TYPE_CAP_MASK_TASR;
5342d116e3eSDmytro Linkin 	case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT:
5352d116e3eSDmytro Linkin 		return MLX5_CAP_QOS(dev, esw_element_type) &
5362d116e3eSDmytro Linkin 		       ELEMENT_TYPE_CAP_MASK_VPORT;
5372d116e3eSDmytro Linkin 	case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT_TC:
5382d116e3eSDmytro Linkin 		return MLX5_CAP_QOS(dev, esw_element_type) &
5392d116e3eSDmytro Linkin 		       ELEMENT_TYPE_CAP_MASK_VPORT_TC;
5402d116e3eSDmytro Linkin 	case SCHEDULING_CONTEXT_ELEMENT_TYPE_PARA_VPORT_TC:
5412d116e3eSDmytro Linkin 		return MLX5_CAP_QOS(dev, esw_element_type) &
5422d116e3eSDmytro Linkin 		       ELEMENT_TYPE_CAP_MASK_PARA_VPORT_TC;
5432d116e3eSDmytro Linkin 	}
5442d116e3eSDmytro Linkin 	return false;
5452d116e3eSDmytro Linkin }
5462d116e3eSDmytro Linkin 
esw_qos_create(struct mlx5_eswitch * esw,struct netlink_ext_ack * extack)54785c5f7c9SDmytro Linkin static int esw_qos_create(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack)
5482d116e3eSDmytro Linkin {
5492d116e3eSDmytro Linkin 	u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
5502d116e3eSDmytro Linkin 	struct mlx5_core_dev *dev = esw->dev;
5512d116e3eSDmytro Linkin 	__be32 *attr;
5522d116e3eSDmytro Linkin 	int err;
5532d116e3eSDmytro Linkin 
5542d116e3eSDmytro Linkin 	if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
55585c5f7c9SDmytro Linkin 		return -EOPNOTSUPP;
5562d116e3eSDmytro Linkin 
5572d116e3eSDmytro Linkin 	if (!esw_qos_element_type_supported(dev, SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR))
55885c5f7c9SDmytro Linkin 		return -EOPNOTSUPP;
5592d116e3eSDmytro Linkin 
5602d116e3eSDmytro Linkin 	MLX5_SET(scheduling_context, tsar_ctx, element_type,
5612d116e3eSDmytro Linkin 		 SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR);
5622d116e3eSDmytro Linkin 
5632d116e3eSDmytro Linkin 	attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes);
5642d116e3eSDmytro Linkin 	*attr = cpu_to_be32(TSAR_ELEMENT_TSAR_TYPE_DWRR << 16);
5652d116e3eSDmytro Linkin 
5662d116e3eSDmytro Linkin 	err = mlx5_create_scheduling_element_cmd(dev,
5672d116e3eSDmytro Linkin 						 SCHEDULING_HIERARCHY_E_SWITCH,
5682d116e3eSDmytro Linkin 						 tsar_ctx,
5692d116e3eSDmytro Linkin 						 &esw->qos.root_tsar_ix);
5702d116e3eSDmytro Linkin 	if (err) {
5711ae258f8SDmytro Linkin 		esw_warn(dev, "E-Switch create root TSAR failed (%d)\n", err);
57285c5f7c9SDmytro Linkin 		return err;
5732d116e3eSDmytro Linkin 	}
5742d116e3eSDmytro Linkin 
575f47e04ebSDmytro Linkin 	INIT_LIST_HEAD(&esw->qos.groups);
5761ae258f8SDmytro Linkin 	if (MLX5_CAP_QOS(dev, log_esw_max_sched_depth)) {
57785c5f7c9SDmytro Linkin 		esw->qos.group0 = __esw_qos_create_rate_group(esw, extack);
5781ae258f8SDmytro Linkin 		if (IS_ERR(esw->qos.group0)) {
5791ae258f8SDmytro Linkin 			esw_warn(dev, "E-Switch create rate group 0 failed (%ld)\n",
5801ae258f8SDmytro Linkin 				 PTR_ERR(esw->qos.group0));
581baf5c001SWei Yongjun 			err = PTR_ERR(esw->qos.group0);
5821ae258f8SDmytro Linkin 			goto err_group0;
5831ae258f8SDmytro Linkin 		}
5841ae258f8SDmytro Linkin 	}
58585c5f7c9SDmytro Linkin 	refcount_set(&esw->qos.refcnt, 1);
58685c5f7c9SDmytro Linkin 
58785c5f7c9SDmytro Linkin 	return 0;
5881ae258f8SDmytro Linkin 
5891ae258f8SDmytro Linkin err_group0:
59085c5f7c9SDmytro Linkin 	if (mlx5_destroy_scheduling_element_cmd(esw->dev, SCHEDULING_HIERARCHY_E_SWITCH,
59185c5f7c9SDmytro Linkin 						esw->qos.root_tsar_ix))
59285c5f7c9SDmytro Linkin 		esw_warn(esw->dev, "E-Switch destroy root TSAR failed.\n");
59385c5f7c9SDmytro Linkin 
59485c5f7c9SDmytro Linkin 	return err;
5952d116e3eSDmytro Linkin }
5962d116e3eSDmytro Linkin 
esw_qos_destroy(struct mlx5_eswitch * esw)59785c5f7c9SDmytro Linkin static void esw_qos_destroy(struct mlx5_eswitch *esw)
5982d116e3eSDmytro Linkin {
5992d116e3eSDmytro Linkin 	int err;
6002d116e3eSDmytro Linkin 
6011ae258f8SDmytro Linkin 	if (esw->qos.group0)
60285c5f7c9SDmytro Linkin 		__esw_qos_destroy_rate_group(esw, esw->qos.group0, NULL);
6032d116e3eSDmytro Linkin 
6042d116e3eSDmytro Linkin 	err = mlx5_destroy_scheduling_element_cmd(esw->dev,
6052d116e3eSDmytro Linkin 						  SCHEDULING_HIERARCHY_E_SWITCH,
6062d116e3eSDmytro Linkin 						  esw->qos.root_tsar_ix);
6072d116e3eSDmytro Linkin 	if (err)
6081ae258f8SDmytro Linkin 		esw_warn(esw->dev, "E-Switch destroy root TSAR failed (%d)\n", err);
60985c5f7c9SDmytro Linkin }
6102d116e3eSDmytro Linkin 
esw_qos_get(struct mlx5_eswitch * esw,struct netlink_ext_ack * extack)61185c5f7c9SDmytro Linkin static int esw_qos_get(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack)
61285c5f7c9SDmytro Linkin {
61385c5f7c9SDmytro Linkin 	int err = 0;
61485c5f7c9SDmytro Linkin 
61585c5f7c9SDmytro Linkin 	lockdep_assert_held(&esw->state_lock);
61685c5f7c9SDmytro Linkin 
61785c5f7c9SDmytro Linkin 	if (!refcount_inc_not_zero(&esw->qos.refcnt)) {
61885c5f7c9SDmytro Linkin 		/* esw_qos_create() set refcount to 1 only on success.
61985c5f7c9SDmytro Linkin 		 * No need to decrement on failure.
62085c5f7c9SDmytro Linkin 		 */
62185c5f7c9SDmytro Linkin 		err = esw_qos_create(esw, extack);
62285c5f7c9SDmytro Linkin 	}
62385c5f7c9SDmytro Linkin 
62485c5f7c9SDmytro Linkin 	return err;
62585c5f7c9SDmytro Linkin }
62685c5f7c9SDmytro Linkin 
esw_qos_put(struct mlx5_eswitch * esw)62785c5f7c9SDmytro Linkin static void esw_qos_put(struct mlx5_eswitch *esw)
62885c5f7c9SDmytro Linkin {
62985c5f7c9SDmytro Linkin 	lockdep_assert_held(&esw->state_lock);
63085c5f7c9SDmytro Linkin 	if (refcount_dec_and_test(&esw->qos.refcnt))
63185c5f7c9SDmytro Linkin 		esw_qos_destroy(esw);
6322d116e3eSDmytro Linkin }
6332d116e3eSDmytro Linkin 
esw_qos_vport_enable(struct mlx5_eswitch * esw,struct mlx5_vport * vport,u32 max_rate,u32 bw_share,struct netlink_ext_ack * extack)634d7df09f5SDmytro Linkin static int esw_qos_vport_enable(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
63585c5f7c9SDmytro Linkin 				u32 max_rate, u32 bw_share, struct netlink_ext_ack *extack)
6362d116e3eSDmytro Linkin {
6372d116e3eSDmytro Linkin 	int err;
6382d116e3eSDmytro Linkin 
6392d116e3eSDmytro Linkin 	lockdep_assert_held(&esw->state_lock);
6402d116e3eSDmytro Linkin 	if (vport->qos.enabled)
641d7df09f5SDmytro Linkin 		return 0;
6422d116e3eSDmytro Linkin 
64385c5f7c9SDmytro Linkin 	err = esw_qos_get(esw, extack);
64485c5f7c9SDmytro Linkin 	if (err)
64585c5f7c9SDmytro Linkin 		return err;
64685c5f7c9SDmytro Linkin 
6470fe132eaSDmytro Linkin 	vport->qos.group = esw->qos.group0;
6482d116e3eSDmytro Linkin 
6490fe132eaSDmytro Linkin 	err = esw_qos_vport_create_sched_element(esw, vport, max_rate, bw_share);
65085c5f7c9SDmytro Linkin 	if (err)
65185c5f7c9SDmytro Linkin 		goto err_out;
65285c5f7c9SDmytro Linkin 
6532d116e3eSDmytro Linkin 	vport->qos.enabled = true;
6543202ea65SDmytro Linkin 	trace_mlx5_esw_vport_qos_create(vport, bw_share, max_rate);
65585c5f7c9SDmytro Linkin 
65685c5f7c9SDmytro Linkin 	return 0;
65785c5f7c9SDmytro Linkin 
65885c5f7c9SDmytro Linkin err_out:
65985c5f7c9SDmytro Linkin 	esw_qos_put(esw);
6602d116e3eSDmytro Linkin 
6612d116e3eSDmytro Linkin 	return err;
6622d116e3eSDmytro Linkin }
6632d116e3eSDmytro Linkin 
mlx5_esw_qos_vport_disable(struct mlx5_eswitch * esw,struct mlx5_vport * vport)6642d116e3eSDmytro Linkin void mlx5_esw_qos_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
6652d116e3eSDmytro Linkin {
6662d116e3eSDmytro Linkin 	int err;
6672d116e3eSDmytro Linkin 
6682d116e3eSDmytro Linkin 	lockdep_assert_held(&esw->state_lock);
66985c5f7c9SDmytro Linkin 	if (!vport->qos.enabled)
6702d116e3eSDmytro Linkin 		return;
6710fe132eaSDmytro Linkin 	WARN(vport->qos.group && vport->qos.group != esw->qos.group0,
6720fe132eaSDmytro Linkin 	     "Disabling QoS on port before detaching it from group");
6732d116e3eSDmytro Linkin 
6742d116e3eSDmytro Linkin 	err = mlx5_destroy_scheduling_element_cmd(esw->dev,
6752d116e3eSDmytro Linkin 						  SCHEDULING_HIERARCHY_E_SWITCH,
6762d116e3eSDmytro Linkin 						  vport->qos.esw_tsar_ix);
6772d116e3eSDmytro Linkin 	if (err)
6782d116e3eSDmytro Linkin 		esw_warn(esw->dev, "E-Switch destroy TSAR vport element failed (vport=%d,err=%d)\n",
6792d116e3eSDmytro Linkin 			 vport->vport, err);
6802d116e3eSDmytro Linkin 
681d7df09f5SDmytro Linkin 	memset(&vport->qos, 0, sizeof(vport->qos));
6823202ea65SDmytro Linkin 	trace_mlx5_esw_vport_qos_destroy(vport);
68385c5f7c9SDmytro Linkin 
68485c5f7c9SDmytro Linkin 	esw_qos_put(esw);
6852d116e3eSDmytro Linkin }
6862d116e3eSDmytro Linkin 
mlx5_esw_qos_set_vport_rate(struct mlx5_eswitch * esw,struct mlx5_vport * vport,u32 max_rate,u32 min_rate)687d7df09f5SDmytro Linkin int mlx5_esw_qos_set_vport_rate(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
688ca49df96SGal Pressman 				u32 max_rate, u32 min_rate)
689d7df09f5SDmytro Linkin {
690d7df09f5SDmytro Linkin 	int err;
691d7df09f5SDmytro Linkin 
692d7df09f5SDmytro Linkin 	lockdep_assert_held(&esw->state_lock);
69385c5f7c9SDmytro Linkin 	err = esw_qos_vport_enable(esw, vport, 0, 0, NULL);
694d7df09f5SDmytro Linkin 	if (err)
695d7df09f5SDmytro Linkin 		return err;
696d7df09f5SDmytro Linkin 
697d7df09f5SDmytro Linkin 	err = esw_qos_set_vport_min_rate(esw, vport, min_rate, NULL);
698d7df09f5SDmytro Linkin 	if (!err)
699d7df09f5SDmytro Linkin 		err = esw_qos_set_vport_max_rate(esw, vport, max_rate, NULL);
700d7df09f5SDmytro Linkin 
701d7df09f5SDmytro Linkin 	return err;
702d7df09f5SDmytro Linkin }
703d7df09f5SDmytro Linkin 
mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch * esw,u16 vport_num,u32 rate_mbps)7042d116e3eSDmytro Linkin int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 rate_mbps)
7052d116e3eSDmytro Linkin {
7062d116e3eSDmytro Linkin 	u32 ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
7072d116e3eSDmytro Linkin 	struct mlx5_vport *vport;
7082d116e3eSDmytro Linkin 	u32 bitmask;
709d7df09f5SDmytro Linkin 	int err;
7102d116e3eSDmytro Linkin 
7112d116e3eSDmytro Linkin 	vport = mlx5_eswitch_get_vport(esw, vport_num);
7122d116e3eSDmytro Linkin 	if (IS_ERR(vport))
7132d116e3eSDmytro Linkin 		return PTR_ERR(vport);
7142d116e3eSDmytro Linkin 
715d7df09f5SDmytro Linkin 	mutex_lock(&esw->state_lock);
716d7df09f5SDmytro Linkin 	if (!vport->qos.enabled) {
717d7df09f5SDmytro Linkin 		/* Eswitch QoS wasn't enabled yet. Enable it and vport QoS. */
71885c5f7c9SDmytro Linkin 		err = esw_qos_vport_enable(esw, vport, rate_mbps, vport->qos.bw_share, NULL);
719d7df09f5SDmytro Linkin 	} else {
7202d116e3eSDmytro Linkin 		MLX5_SET(scheduling_context, ctx, max_average_bw, rate_mbps);
7212d116e3eSDmytro Linkin 
722d7df09f5SDmytro Linkin 		bitmask = MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
723d7df09f5SDmytro Linkin 		err = mlx5_modify_scheduling_element_cmd(esw->dev,
7242d116e3eSDmytro Linkin 							 SCHEDULING_HIERARCHY_E_SWITCH,
7252d116e3eSDmytro Linkin 							 ctx,
7262d116e3eSDmytro Linkin 							 vport->qos.esw_tsar_ix,
7272d116e3eSDmytro Linkin 							 bitmask);
7282d116e3eSDmytro Linkin 	}
729d7df09f5SDmytro Linkin 	mutex_unlock(&esw->state_lock);
730d7df09f5SDmytro Linkin 
731d7df09f5SDmytro Linkin 	return err;
732d7df09f5SDmytro Linkin }
733ad34f02fSDmytro Linkin 
734ad34f02fSDmytro Linkin #define MLX5_LINKSPEED_UNIT 125000 /* 1Mbps in Bps */
735ad34f02fSDmytro Linkin 
736ad34f02fSDmytro Linkin /* Converts bytes per second value passed in a pointer into megabits per
737ad34f02fSDmytro Linkin  * second, rewriting last. If converted rate exceed link speed or is not a
738ad34f02fSDmytro Linkin  * fraction of Mbps - returns error.
739ad34f02fSDmytro Linkin  */
esw_qos_devlink_rate_to_mbps(struct mlx5_core_dev * mdev,const char * name,u64 * rate,struct netlink_ext_ack * extack)740ad34f02fSDmytro Linkin static int esw_qos_devlink_rate_to_mbps(struct mlx5_core_dev *mdev, const char *name,
741ad34f02fSDmytro Linkin 					u64 *rate, struct netlink_ext_ack *extack)
742ad34f02fSDmytro Linkin {
743*58f6d9d0SGal Pressman 	u32 link_speed_max, remainder;
744ad34f02fSDmytro Linkin 	u64 value;
745ad34f02fSDmytro Linkin 	int err;
746ad34f02fSDmytro Linkin 
747028522e2SGal Pressman 	err = mlx5_port_max_linkspeed(mdev, &link_speed_max);
748ad34f02fSDmytro Linkin 	if (err) {
749ad34f02fSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "Failed to get link maximum speed");
750ad34f02fSDmytro Linkin 		return err;
751ad34f02fSDmytro Linkin 	}
752ad34f02fSDmytro Linkin 
753*58f6d9d0SGal Pressman 	value = div_u64_rem(*rate, MLX5_LINKSPEED_UNIT, &remainder);
754*58f6d9d0SGal Pressman 	if (remainder) {
755ad34f02fSDmytro Linkin 		pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n",
756ad34f02fSDmytro Linkin 		       name, *rate);
757ad34f02fSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps");
758ad34f02fSDmytro Linkin 		return -EINVAL;
759ad34f02fSDmytro Linkin 	}
760ad34f02fSDmytro Linkin 
761ad34f02fSDmytro Linkin 	if (value > link_speed_max) {
762ad34f02fSDmytro Linkin 		pr_err("%s rate value %lluMbps exceed link maximum speed %u.\n",
763ad34f02fSDmytro Linkin 		       name, value, link_speed_max);
764ad34f02fSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed");
765ad34f02fSDmytro Linkin 		return -EINVAL;
766ad34f02fSDmytro Linkin 	}
767ad34f02fSDmytro Linkin 
768ad34f02fSDmytro Linkin 	*rate = value;
769ad34f02fSDmytro Linkin 	return 0;
770ad34f02fSDmytro Linkin }
771ad34f02fSDmytro Linkin 
772ad34f02fSDmytro Linkin /* Eswitch devlink rate API */
773ad34f02fSDmytro Linkin 
mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate * rate_leaf,void * priv,u64 tx_share,struct netlink_ext_ack * extack)774ad34f02fSDmytro Linkin int mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void *priv,
775ad34f02fSDmytro Linkin 					    u64 tx_share, struct netlink_ext_ack *extack)
776ad34f02fSDmytro Linkin {
777ad34f02fSDmytro Linkin 	struct mlx5_vport *vport = priv;
778ad34f02fSDmytro Linkin 	struct mlx5_eswitch *esw;
779ad34f02fSDmytro Linkin 	int err;
780ad34f02fSDmytro Linkin 
781ad34f02fSDmytro Linkin 	esw = vport->dev->priv.eswitch;
782ad34f02fSDmytro Linkin 	if (!mlx5_esw_allowed(esw))
783ad34f02fSDmytro Linkin 		return -EPERM;
784ad34f02fSDmytro Linkin 
785ad34f02fSDmytro Linkin 	err = esw_qos_devlink_rate_to_mbps(vport->dev, "tx_share", &tx_share, extack);
786ad34f02fSDmytro Linkin 	if (err)
787ad34f02fSDmytro Linkin 		return err;
788ad34f02fSDmytro Linkin 
789ad34f02fSDmytro Linkin 	mutex_lock(&esw->state_lock);
79085c5f7c9SDmytro Linkin 	err = esw_qos_vport_enable(esw, vport, 0, 0, extack);
791d7df09f5SDmytro Linkin 	if (err)
792d7df09f5SDmytro Linkin 		goto unlock;
793d7df09f5SDmytro Linkin 
794d7df09f5SDmytro Linkin 	err = esw_qos_set_vport_min_rate(esw, vport, tx_share, extack);
795d7df09f5SDmytro Linkin unlock:
796ad34f02fSDmytro Linkin 	mutex_unlock(&esw->state_lock);
797ad34f02fSDmytro Linkin 	return err;
798ad34f02fSDmytro Linkin }
799ad34f02fSDmytro Linkin 
mlx5_esw_devlink_rate_leaf_tx_max_set(struct devlink_rate * rate_leaf,void * priv,u64 tx_max,struct netlink_ext_ack * extack)800ad34f02fSDmytro Linkin int mlx5_esw_devlink_rate_leaf_tx_max_set(struct devlink_rate *rate_leaf, void *priv,
801ad34f02fSDmytro Linkin 					  u64 tx_max, struct netlink_ext_ack *extack)
802ad34f02fSDmytro Linkin {
803ad34f02fSDmytro Linkin 	struct mlx5_vport *vport = priv;
804ad34f02fSDmytro Linkin 	struct mlx5_eswitch *esw;
805ad34f02fSDmytro Linkin 	int err;
806ad34f02fSDmytro Linkin 
807ad34f02fSDmytro Linkin 	esw = vport->dev->priv.eswitch;
808ad34f02fSDmytro Linkin 	if (!mlx5_esw_allowed(esw))
809ad34f02fSDmytro Linkin 		return -EPERM;
810ad34f02fSDmytro Linkin 
811ad34f02fSDmytro Linkin 	err = esw_qos_devlink_rate_to_mbps(vport->dev, "tx_max", &tx_max, extack);
812ad34f02fSDmytro Linkin 	if (err)
813ad34f02fSDmytro Linkin 		return err;
814ad34f02fSDmytro Linkin 
815ad34f02fSDmytro Linkin 	mutex_lock(&esw->state_lock);
81685c5f7c9SDmytro Linkin 	err = esw_qos_vport_enable(esw, vport, 0, 0, extack);
817d7df09f5SDmytro Linkin 	if (err)
818d7df09f5SDmytro Linkin 		goto unlock;
819d7df09f5SDmytro Linkin 
820d7df09f5SDmytro Linkin 	err = esw_qos_set_vport_max_rate(esw, vport, tx_max, extack);
821d7df09f5SDmytro Linkin unlock:
822ad34f02fSDmytro Linkin 	mutex_unlock(&esw->state_lock);
823ad34f02fSDmytro Linkin 	return err;
824ad34f02fSDmytro Linkin }
8251ae258f8SDmytro Linkin 
mlx5_esw_devlink_rate_node_tx_share_set(struct devlink_rate * rate_node,void * priv,u64 tx_share,struct netlink_ext_ack * extack)826f47e04ebSDmytro Linkin int mlx5_esw_devlink_rate_node_tx_share_set(struct devlink_rate *rate_node, void *priv,
827f47e04ebSDmytro Linkin 					    u64 tx_share, struct netlink_ext_ack *extack)
828f47e04ebSDmytro Linkin {
829f47e04ebSDmytro Linkin 	struct mlx5_core_dev *dev = devlink_priv(rate_node->devlink);
830f47e04ebSDmytro Linkin 	struct mlx5_eswitch *esw = dev->priv.eswitch;
831f47e04ebSDmytro Linkin 	struct mlx5_esw_rate_group *group = priv;
832f47e04ebSDmytro Linkin 	int err;
833f47e04ebSDmytro Linkin 
834f47e04ebSDmytro Linkin 	err = esw_qos_devlink_rate_to_mbps(dev, "tx_share", &tx_share, extack);
835f47e04ebSDmytro Linkin 	if (err)
836f47e04ebSDmytro Linkin 		return err;
837f47e04ebSDmytro Linkin 
838f47e04ebSDmytro Linkin 	mutex_lock(&esw->state_lock);
839f47e04ebSDmytro Linkin 	err = esw_qos_set_group_min_rate(esw, group, tx_share, extack);
840f47e04ebSDmytro Linkin 	mutex_unlock(&esw->state_lock);
841f47e04ebSDmytro Linkin 	return err;
842f47e04ebSDmytro Linkin }
843f47e04ebSDmytro Linkin 
mlx5_esw_devlink_rate_node_tx_max_set(struct devlink_rate * rate_node,void * priv,u64 tx_max,struct netlink_ext_ack * extack)844f47e04ebSDmytro Linkin int mlx5_esw_devlink_rate_node_tx_max_set(struct devlink_rate *rate_node, void *priv,
845f47e04ebSDmytro Linkin 					  u64 tx_max, struct netlink_ext_ack *extack)
846f47e04ebSDmytro Linkin {
847f47e04ebSDmytro Linkin 	struct mlx5_core_dev *dev = devlink_priv(rate_node->devlink);
848f47e04ebSDmytro Linkin 	struct mlx5_eswitch *esw = dev->priv.eswitch;
849f47e04ebSDmytro Linkin 	struct mlx5_esw_rate_group *group = priv;
850f47e04ebSDmytro Linkin 	int err;
851f47e04ebSDmytro Linkin 
852f47e04ebSDmytro Linkin 	err = esw_qos_devlink_rate_to_mbps(dev, "tx_max", &tx_max, extack);
853f47e04ebSDmytro Linkin 	if (err)
854f47e04ebSDmytro Linkin 		return err;
855f47e04ebSDmytro Linkin 
856f47e04ebSDmytro Linkin 	mutex_lock(&esw->state_lock);
857f47e04ebSDmytro Linkin 	err = esw_qos_set_group_max_rate(esw, group, tx_max, extack);
858f47e04ebSDmytro Linkin 	mutex_unlock(&esw->state_lock);
859f47e04ebSDmytro Linkin 	return err;
860f47e04ebSDmytro Linkin }
861f47e04ebSDmytro Linkin 
mlx5_esw_devlink_rate_node_new(struct devlink_rate * rate_node,void ** priv,struct netlink_ext_ack * extack)8621ae258f8SDmytro Linkin int mlx5_esw_devlink_rate_node_new(struct devlink_rate *rate_node, void **priv,
8631ae258f8SDmytro Linkin 				   struct netlink_ext_ack *extack)
8641ae258f8SDmytro Linkin {
8651ae258f8SDmytro Linkin 	struct mlx5_esw_rate_group *group;
8661ae258f8SDmytro Linkin 	struct mlx5_eswitch *esw;
8671ae258f8SDmytro Linkin 	int err = 0;
8681ae258f8SDmytro Linkin 
8691ae258f8SDmytro Linkin 	esw = mlx5_devlink_eswitch_get(rate_node->devlink);
8701ae258f8SDmytro Linkin 	if (IS_ERR(esw))
8711ae258f8SDmytro Linkin 		return PTR_ERR(esw);
8721ae258f8SDmytro Linkin 
8731ae258f8SDmytro Linkin 	mutex_lock(&esw->state_lock);
8741ae258f8SDmytro Linkin 	if (esw->mode != MLX5_ESWITCH_OFFLOADS) {
8751ae258f8SDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack,
8761ae258f8SDmytro Linkin 				   "Rate node creation supported only in switchdev mode");
8771ae258f8SDmytro Linkin 		err = -EOPNOTSUPP;
8781ae258f8SDmytro Linkin 		goto unlock;
8791ae258f8SDmytro Linkin 	}
8801ae258f8SDmytro Linkin 
8811ae258f8SDmytro Linkin 	group = esw_qos_create_rate_group(esw, extack);
8821ae258f8SDmytro Linkin 	if (IS_ERR(group)) {
8831ae258f8SDmytro Linkin 		err = PTR_ERR(group);
8841ae258f8SDmytro Linkin 		goto unlock;
8851ae258f8SDmytro Linkin 	}
8861ae258f8SDmytro Linkin 
8871ae258f8SDmytro Linkin 	*priv = group;
8881ae258f8SDmytro Linkin unlock:
8891ae258f8SDmytro Linkin 	mutex_unlock(&esw->state_lock);
8901ae258f8SDmytro Linkin 	return err;
8911ae258f8SDmytro Linkin }
8921ae258f8SDmytro Linkin 
mlx5_esw_devlink_rate_node_del(struct devlink_rate * rate_node,void * priv,struct netlink_ext_ack * extack)8931ae258f8SDmytro Linkin int mlx5_esw_devlink_rate_node_del(struct devlink_rate *rate_node, void *priv,
8941ae258f8SDmytro Linkin 				   struct netlink_ext_ack *extack)
8951ae258f8SDmytro Linkin {
8961ae258f8SDmytro Linkin 	struct mlx5_esw_rate_group *group = priv;
8971ae258f8SDmytro Linkin 	struct mlx5_eswitch *esw;
8981ae258f8SDmytro Linkin 	int err;
8991ae258f8SDmytro Linkin 
9001ae258f8SDmytro Linkin 	esw = mlx5_devlink_eswitch_get(rate_node->devlink);
9011ae258f8SDmytro Linkin 	if (IS_ERR(esw))
9021ae258f8SDmytro Linkin 		return PTR_ERR(esw);
9031ae258f8SDmytro Linkin 
9041ae258f8SDmytro Linkin 	mutex_lock(&esw->state_lock);
9051ae258f8SDmytro Linkin 	err = esw_qos_destroy_rate_group(esw, group, extack);
9061ae258f8SDmytro Linkin 	mutex_unlock(&esw->state_lock);
9071ae258f8SDmytro Linkin 	return err;
9081ae258f8SDmytro Linkin }
9090fe132eaSDmytro Linkin 
mlx5_esw_qos_vport_update_group(struct mlx5_eswitch * esw,struct mlx5_vport * vport,struct mlx5_esw_rate_group * group,struct netlink_ext_ack * extack)9100fe132eaSDmytro Linkin int mlx5_esw_qos_vport_update_group(struct mlx5_eswitch *esw,
9110fe132eaSDmytro Linkin 				    struct mlx5_vport *vport,
9120fe132eaSDmytro Linkin 				    struct mlx5_esw_rate_group *group,
9130fe132eaSDmytro Linkin 				    struct netlink_ext_ack *extack)
9140fe132eaSDmytro Linkin {
915909ffe46SChris Mi 	int err = 0;
9160fe132eaSDmytro Linkin 
9170fe132eaSDmytro Linkin 	mutex_lock(&esw->state_lock);
918909ffe46SChris Mi 	if (!vport->qos.enabled && !group)
919909ffe46SChris Mi 		goto unlock;
920909ffe46SChris Mi 
92185c5f7c9SDmytro Linkin 	err = esw_qos_vport_enable(esw, vport, 0, 0, extack);
922d7df09f5SDmytro Linkin 	if (!err)
9230fe132eaSDmytro Linkin 		err = esw_qos_vport_update_group(esw, vport, group, extack);
924909ffe46SChris Mi unlock:
9250fe132eaSDmytro Linkin 	mutex_unlock(&esw->state_lock);
9260fe132eaSDmytro Linkin 	return err;
9270fe132eaSDmytro Linkin }
9280fe132eaSDmytro Linkin 
mlx5_esw_devlink_rate_parent_set(struct devlink_rate * devlink_rate,struct devlink_rate * parent,void * priv,void * parent_priv,struct netlink_ext_ack * extack)9290fe132eaSDmytro Linkin int mlx5_esw_devlink_rate_parent_set(struct devlink_rate *devlink_rate,
9300fe132eaSDmytro Linkin 				     struct devlink_rate *parent,
9310fe132eaSDmytro Linkin 				     void *priv, void *parent_priv,
9320fe132eaSDmytro Linkin 				     struct netlink_ext_ack *extack)
9330fe132eaSDmytro Linkin {
9340fe132eaSDmytro Linkin 	struct mlx5_esw_rate_group *group;
9350fe132eaSDmytro Linkin 	struct mlx5_vport *vport = priv;
9360fe132eaSDmytro Linkin 
9370fe132eaSDmytro Linkin 	if (!parent)
9380fe132eaSDmytro Linkin 		return mlx5_esw_qos_vport_update_group(vport->dev->priv.eswitch,
9390fe132eaSDmytro Linkin 						       vport, NULL, extack);
9400fe132eaSDmytro Linkin 
9410fe132eaSDmytro Linkin 	group = parent_priv;
9420fe132eaSDmytro Linkin 	return mlx5_esw_qos_vport_update_group(vport->dev->priv.eswitch, vport, group, extack);
9430fe132eaSDmytro Linkin }
944