xref: /linux/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3 
4 #include "eswitch.h"
5 #include "lib/mlx5.h"
6 #include "esw/qos.h"
7 #include "en/port.h"
8 #define CREATE_TRACE_POINTS
9 #include "diag/qos_tracepoint.h"
10 
11 /* Minimum supported BW share value by the HW is 1 Mbit/sec */
12 #define MLX5_MIN_BW_SHARE 1
13 
14 enum sched_node_type {
15 	SCHED_NODE_TYPE_ROOT,
16 	SCHED_NODE_TYPE_VPORTS_TSAR,
17 	SCHED_NODE_TYPE_VPORT,
18 	SCHED_NODE_TYPE_TC_ARBITER_TSAR,
19 	SCHED_NODE_TYPE_RATE_LIMITER,
20 	SCHED_NODE_TYPE_VPORT_TC,
21 	SCHED_NODE_TYPE_VPORTS_TC_TSAR,
22 };
23 
24 static const char * const sched_node_type_str[] = {
25 	[SCHED_NODE_TYPE_VPORTS_TSAR] = "vports TSAR",
26 	[SCHED_NODE_TYPE_VPORT] = "vport",
27 	[SCHED_NODE_TYPE_TC_ARBITER_TSAR] = "TC Arbiter TSAR",
28 	[SCHED_NODE_TYPE_RATE_LIMITER] = "Rate Limiter",
29 	[SCHED_NODE_TYPE_VPORT_TC] = "vport TC",
30 	[SCHED_NODE_TYPE_VPORTS_TC_TSAR] = "vports TC TSAR",
31 };
32 
33 struct mlx5_esw_sched_node {
34 	u32 ix;
35 	/* Bandwidth parameters. */
36 	u32 max_rate;
37 	u32 min_rate;
38 	/* A computed value indicating relative min_rate between node's children. */
39 	u32 bw_share;
40 	/* The parent node in the rate hierarchy. */
41 	struct mlx5_esw_sched_node *parent;
42 	/* Entry in the parent node's children list. */
43 	struct list_head entry;
44 	/* The type of this node in the rate hierarchy. */
45 	enum sched_node_type type;
46 	/* The eswitch this node belongs to. */
47 	struct mlx5_eswitch *esw;
48 	/* The children nodes of this node, empty list for leaf nodes.
49 	 * Can be from multiple E-Switches.
50 	 */
51 	struct list_head children;
52 	/* Valid only if this node is associated with a vport. */
53 	struct mlx5_vport *vport;
54 	/* Level in the hierarchy. The root node level is 1. */
55 	u8 level;
56 	/* Valid only when this node represents a traffic class. */
57 	u8 tc;
58 	/* Valid only for a TC arbiter node or vport TC arbiter. */
59 	u32 tc_bw[DEVLINK_RATE_TCS_MAX];
60 };
61 
62 /* Locking notes:
63  * QoS changes are normally protected by the shd lock. But on older HW shd
64  * might not be created at all, so there needs to be a fallback serialization
65  * mechanism. This is esw->state_lock.
66  * Callers into QoS hold a combination of RTNL, devlink instance lock and
67  * esw->state_lock. Devlink rate ops additionally hold the shd lock if it
68  * exists.
69  * - VF rate ops use esw_qos_lock/esw_qos_unlock.
70  * - callers with esw->state_lock held use esw_qos_shd_lock/esw_qos_shd_unlock.
71  * - devlink callers use esw_qos_devlink_lock/esw_qos_devlink_unlock.
72  */
esw_assert_qos_lock_held(struct mlx5_core_dev * dev)73 static void esw_assert_qos_lock_held(struct mlx5_core_dev *dev)
74 {
75 	if (dev->shd)
76 		devl_assert_locked(dev->shd);
77 	else
78 		lockdep_assert_held(&dev->priv.eswitch->state_lock);
79 }
80 
esw_qos_lock(struct mlx5_core_dev * dev)81 static void esw_qos_lock(struct mlx5_core_dev *dev)
82 {
83 	if (dev->shd)
84 		devl_lock(dev->shd);
85 	else
86 		mutex_lock(&dev->priv.eswitch->state_lock);
87 }
88 
esw_qos_unlock(struct mlx5_core_dev * dev)89 static void esw_qos_unlock(struct mlx5_core_dev *dev)
90 {
91 	if (dev->shd)
92 		devl_unlock(dev->shd);
93 	else
94 		mutex_unlock(&dev->priv.eswitch->state_lock);
95 }
96 
esw_qos_shd_lock(struct mlx5_core_dev * dev)97 static void esw_qos_shd_lock(struct mlx5_core_dev *dev)
98 {
99 	if (dev->shd)
100 		devl_lock(dev->shd);
101 }
102 
esw_qos_shd_unlock(struct mlx5_core_dev * dev)103 static void esw_qos_shd_unlock(struct mlx5_core_dev *dev)
104 {
105 	if (dev->shd)
106 		devl_unlock(dev->shd);
107 }
108 
esw_qos_devlink_lock(struct mlx5_core_dev * dev)109 static void esw_qos_devlink_lock(struct mlx5_core_dev *dev)
110 {
111 	if (!dev->shd)
112 		mutex_lock(&dev->priv.eswitch->state_lock);
113 }
114 
esw_qos_devlink_unlock(struct mlx5_core_dev * dev)115 static void esw_qos_devlink_unlock(struct mlx5_core_dev *dev)
116 {
117 	if (!dev->shd)
118 		mutex_unlock(&dev->priv.eswitch->state_lock);
119 }
120 
esw_qos_num_tcs(struct mlx5_core_dev * dev)121 static int esw_qos_num_tcs(struct mlx5_core_dev *dev)
122 {
123 	int num_tcs = mlx5_max_tc(dev) + 1;
124 
125 	return num_tcs < DEVLINK_RATE_TCS_MAX ? num_tcs : DEVLINK_RATE_TCS_MAX;
126 }
127 
esw_qos_node_set_parent(struct mlx5_esw_sched_node * node,struct mlx5_esw_sched_node * parent)128 static void esw_qos_node_set_parent(struct mlx5_esw_sched_node *node,
129 				    struct mlx5_esw_sched_node *parent)
130 {
131 	node->parent = parent;
132 	node->esw = parent->esw;
133 	node->level = parent->level + 1;
134 	list_del(&node->entry);
135 	list_add_tail(&node->entry, &parent->children);
136 }
137 
esw_qos_nodes_set_parent(struct list_head * nodes,struct mlx5_esw_sched_node * parent)138 static void esw_qos_nodes_set_parent(struct list_head *nodes,
139 				     struct mlx5_esw_sched_node *parent)
140 {
141 	struct mlx5_esw_sched_node *node, *tmp;
142 
143 	list_for_each_entry_safe(node, tmp, nodes, entry) {
144 		esw_qos_node_set_parent(node, parent);
145 		if (!list_empty(&node->children) &&
146 		    parent->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) {
147 			struct mlx5_esw_sched_node *child;
148 
149 			list_for_each_entry(child, &node->children, entry) {
150 				struct mlx5_vport *vport = child->vport;
151 
152 				if (vport)
153 					vport->qos.sched_node->parent = parent;
154 			}
155 		}
156 	}
157 }
158 
mlx5_esw_qos_vport_qos_free(struct mlx5_vport * vport)159 void mlx5_esw_qos_vport_qos_free(struct mlx5_vport *vport)
160 {
161 	if (vport->qos.sched_nodes) {
162 		int num_tcs = esw_qos_num_tcs(vport->qos.sched_node->esw->dev);
163 		int i;
164 
165 		for (i = 0; i < num_tcs; i++)
166 			kfree(vport->qos.sched_nodes[i]);
167 		kfree(vport->qos.sched_nodes);
168 	}
169 
170 	kfree(vport->qos.sched_node);
171 	memset(&vport->qos, 0, sizeof(vport->qos));
172 }
173 
mlx5_esw_qos_vport_get_sched_elem_ix(const struct mlx5_vport * vport)174 u32 mlx5_esw_qos_vport_get_sched_elem_ix(const struct mlx5_vport *vport)
175 {
176 	if (!vport->qos.sched_node)
177 		return 0;
178 
179 	return vport->qos.sched_node->ix;
180 }
181 
182 struct mlx5_esw_sched_node *
mlx5_esw_qos_vport_get_parent(const struct mlx5_vport * vport)183 mlx5_esw_qos_vport_get_parent(const struct mlx5_vport *vport)
184 {
185 	if (!vport->qos.sched_node)
186 		return NULL;
187 
188 	return vport->qos.sched_node->parent;
189 }
190 
esw_qos_sched_elem_warn(struct mlx5_esw_sched_node * node,int err,const char * op)191 static void esw_qos_sched_elem_warn(struct mlx5_esw_sched_node *node, int err, const char *op)
192 {
193 	switch (node->type) {
194 	case SCHED_NODE_TYPE_VPORTS_TC_TSAR:
195 		esw_warn(node->esw->dev,
196 			 "E-Switch %s %s scheduling element failed (tc=%d,err=%d)\n",
197 			 op, sched_node_type_str[node->type], node->tc, err);
198 		break;
199 	case SCHED_NODE_TYPE_VPORT_TC:
200 		esw_warn(node->esw->dev,
201 			 "E-Switch %s %s scheduling element failed (vport=%d,tc=%d,err=%d)\n",
202 			 op,
203 			 sched_node_type_str[node->type],
204 			 node->vport->vport, node->tc, err);
205 		break;
206 	case SCHED_NODE_TYPE_VPORT:
207 		esw_warn(node->esw->dev,
208 			 "E-Switch %s %s scheduling element failed (vport=%d,err=%d)\n",
209 			 op, sched_node_type_str[node->type], node->vport->vport, err);
210 		break;
211 	case SCHED_NODE_TYPE_RATE_LIMITER:
212 	case SCHED_NODE_TYPE_TC_ARBITER_TSAR:
213 	case SCHED_NODE_TYPE_VPORTS_TSAR:
214 		esw_warn(node->esw->dev,
215 			 "E-Switch %s %s scheduling element failed (err=%d)\n",
216 			 op, sched_node_type_str[node->type], err);
217 		break;
218 	default:
219 		esw_warn(node->esw->dev,
220 			 "E-Switch %s scheduling element failed (err=%d)\n",
221 			 op, err);
222 		break;
223 	}
224 }
225 
esw_qos_node_create_sched_element(struct mlx5_esw_sched_node * node,void * ctx,struct netlink_ext_ack * extack)226 static int esw_qos_node_create_sched_element(struct mlx5_esw_sched_node *node, void *ctx,
227 					     struct netlink_ext_ack *extack)
228 {
229 	int err;
230 
231 	err = mlx5_create_scheduling_element_cmd(node->esw->dev, SCHEDULING_HIERARCHY_E_SWITCH, ctx,
232 						 &node->ix);
233 	if (err) {
234 		esw_qos_sched_elem_warn(node, err, "create");
235 		NL_SET_ERR_MSG_MOD(extack, "E-Switch create scheduling element failed");
236 	}
237 
238 	return err;
239 }
240 
esw_qos_node_destroy_sched_element(struct mlx5_esw_sched_node * node,struct netlink_ext_ack * extack)241 static int esw_qos_node_destroy_sched_element(struct mlx5_esw_sched_node *node,
242 					      struct netlink_ext_ack *extack)
243 {
244 	int err;
245 
246 	err = mlx5_destroy_scheduling_element_cmd(node->esw->dev,
247 						  SCHEDULING_HIERARCHY_E_SWITCH,
248 						  node->ix);
249 	if (err) {
250 		esw_qos_sched_elem_warn(node, err, "destroy");
251 		NL_SET_ERR_MSG_MOD(extack, "E-Switch destroying scheduling element failed.");
252 	}
253 
254 	return err;
255 }
256 
esw_qos_sched_elem_config(struct mlx5_esw_sched_node * node,u32 max_rate,u32 bw_share,struct netlink_ext_ack * extack)257 static int esw_qos_sched_elem_config(struct mlx5_esw_sched_node *node, u32 max_rate, u32 bw_share,
258 				     struct netlink_ext_ack *extack)
259 {
260 	u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
261 	struct mlx5_core_dev *dev = node->esw->dev;
262 	u32 bitmask = 0;
263 	int err;
264 
265 	if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
266 		return -EOPNOTSUPP;
267 
268 	if (bw_share && (!MLX5_CAP_QOS(dev, esw_bw_share) ||
269 			 MLX5_CAP_QOS(dev, max_tsar_bw_share) < MLX5_MIN_BW_SHARE))
270 		return -EOPNOTSUPP;
271 
272 	if (node->max_rate == max_rate && node->bw_share == bw_share)
273 		return 0;
274 
275 	if (node->max_rate != max_rate) {
276 		MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
277 		bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
278 	}
279 	if (node->bw_share != bw_share) {
280 		MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
281 		bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE;
282 	}
283 
284 	err = mlx5_modify_scheduling_element_cmd(dev,
285 						 SCHEDULING_HIERARCHY_E_SWITCH,
286 						 sched_ctx,
287 						 node->ix,
288 						 bitmask);
289 	if (err) {
290 		esw_qos_sched_elem_warn(node, err, "modify");
291 		NL_SET_ERR_MSG_MOD(extack, "E-Switch modify scheduling element failed");
292 
293 		return err;
294 	}
295 
296 	node->max_rate = max_rate;
297 	node->bw_share = bw_share;
298 	if (node->type == SCHED_NODE_TYPE_VPORTS_TSAR)
299 		trace_mlx5_esw_node_qos_config(dev, node, node->ix, bw_share, max_rate);
300 	else if (node->type == SCHED_NODE_TYPE_VPORT)
301 		trace_mlx5_esw_vport_qos_config(dev, node->vport, bw_share, max_rate);
302 
303 	return 0;
304 }
305 
esw_qos_create_rate_limit_element(struct mlx5_esw_sched_node * node,struct netlink_ext_ack * extack)306 static int esw_qos_create_rate_limit_element(struct mlx5_esw_sched_node *node,
307 					     struct netlink_ext_ack *extack)
308 {
309 	u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
310 
311 	if (!mlx5_qos_element_type_supported(
312 		node->esw->dev,
313 		SCHEDULING_CONTEXT_ELEMENT_TYPE_RATE_LIMIT,
314 		SCHEDULING_HIERARCHY_E_SWITCH))
315 		return -EOPNOTSUPP;
316 
317 	MLX5_SET(scheduling_context, sched_ctx, max_average_bw, node->max_rate);
318 	MLX5_SET(scheduling_context, sched_ctx, element_type,
319 		 SCHEDULING_CONTEXT_ELEMENT_TYPE_RATE_LIMIT);
320 
321 	return esw_qos_node_create_sched_element(node, sched_ctx, extack);
322 }
323 
324 static u32
esw_qos_calculate_min_rate_divider(struct mlx5_esw_sched_node * parent)325 esw_qos_calculate_min_rate_divider(struct mlx5_esw_sched_node *parent)
326 {
327 	u32 fw_max_bw_share = MLX5_CAP_QOS(parent->esw->dev, max_tsar_bw_share);
328 	struct mlx5_esw_sched_node *node;
329 	u32 max_guarantee = 0;
330 
331 	/* Find max min_rate across all nodes.
332 	 * This will correspond to fw_max_bw_share in the final bw_share calculation.
333 	 */
334 	list_for_each_entry(node, &parent->children, entry)
335 		if (node->min_rate > max_guarantee)
336 			max_guarantee = node->min_rate;
337 
338 	if (max_guarantee)
339 		return max_t(u32, max_guarantee / fw_max_bw_share, 1);
340 
341 	/* If the node nodes has min_rate configured, a divider of 0 sets all
342 	 * nodes' bw_share to 0, effectively disabling min guarantees.
343 	 */
344 	return 0;
345 }
346 
esw_qos_calc_bw_share(u32 value,u32 divider,u32 fw_max)347 static u32 esw_qos_calc_bw_share(u32 value, u32 divider, u32 fw_max)
348 {
349 	if (!divider)
350 		return 0;
351 	return min_t(u32, fw_max,
352 		     max_t(u32,
353 			   DIV_ROUND_UP(value, divider), MLX5_MIN_BW_SHARE));
354 }
355 
esw_qos_update_sched_node_bw_share(struct mlx5_esw_sched_node * node,u32 divider,struct netlink_ext_ack * extack)356 static void esw_qos_update_sched_node_bw_share(struct mlx5_esw_sched_node *node,
357 					       u32 divider,
358 					       struct netlink_ext_ack *extack)
359 {
360 	u32 fw_max_bw_share = MLX5_CAP_QOS(node->esw->dev, max_tsar_bw_share);
361 	u32 bw_share;
362 
363 	bw_share = esw_qos_calc_bw_share(node->min_rate, divider, fw_max_bw_share);
364 
365 	esw_qos_sched_elem_config(node, node->max_rate, bw_share, extack);
366 }
367 
esw_qos_normalize_min_rate(struct mlx5_esw_sched_node * parent,struct netlink_ext_ack * extack)368 static void esw_qos_normalize_min_rate(struct mlx5_esw_sched_node *parent,
369 				       struct netlink_ext_ack *extack)
370 {
371 	u32 divider = esw_qos_calculate_min_rate_divider(parent);
372 	struct mlx5_esw_sched_node *node;
373 
374 	list_for_each_entry(node, &parent->children, entry) {
375 		/* Vports TC TSARs don't have a minimum rate configured,
376 		 * so there's no need to update the bw_share on them.
377 		 */
378 		if (node->type != SCHED_NODE_TYPE_VPORTS_TC_TSAR) {
379 			esw_qos_update_sched_node_bw_share(node, divider,
380 							   extack);
381 		}
382 
383 		if (list_empty(&node->children))
384 			continue;
385 
386 		esw_qos_normalize_min_rate(node, extack);
387 	}
388 }
389 
esw_qos_calculate_tc_bw_divider(u32 * tc_bw)390 static u32 esw_qos_calculate_tc_bw_divider(u32 *tc_bw)
391 {
392 	u32 total = 0;
393 	int i;
394 
395 	for (i = 0; i < DEVLINK_RATE_TCS_MAX; i++)
396 		total += tc_bw[i];
397 
398 	/* If total is zero, tc-bw config is disabled and we shouldn't reach
399 	 * here.
400 	 */
401 	return WARN_ON(!total) ? 1 : total;
402 }
403 
esw_qos_set_node_min_rate(struct mlx5_esw_sched_node * node,u32 min_rate,struct netlink_ext_ack * extack)404 static int esw_qos_set_node_min_rate(struct mlx5_esw_sched_node *node,
405 				     u32 min_rate, struct netlink_ext_ack *extack)
406 {
407 	if (min_rate == node->min_rate)
408 		return 0;
409 
410 	node->min_rate = min_rate;
411 	esw_qos_normalize_min_rate(node->parent, extack);
412 	return 0;
413 }
414 
415 static int
esw_qos_create_node_sched_elem(struct mlx5_core_dev * dev,u32 parent_element_id,u32 max_rate,u32 bw_share,u32 * tsar_ix)416 esw_qos_create_node_sched_elem(struct mlx5_core_dev *dev, u32 parent_element_id,
417 			       u32 max_rate, u32 bw_share, u32 *tsar_ix)
418 {
419 	u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
420 	void *attr;
421 
422 	if (!mlx5_qos_element_type_supported(dev,
423 					     SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR,
424 					     SCHEDULING_HIERARCHY_E_SWITCH) ||
425 	    !mlx5_qos_tsar_type_supported(dev,
426 					  TSAR_ELEMENT_TSAR_TYPE_DWRR,
427 					  SCHEDULING_HIERARCHY_E_SWITCH))
428 		return -EOPNOTSUPP;
429 
430 	MLX5_SET(scheduling_context, tsar_ctx, element_type,
431 		 SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR);
432 	MLX5_SET(scheduling_context, tsar_ctx, parent_element_id,
433 		 parent_element_id);
434 	MLX5_SET(scheduling_context, tsar_ctx, max_average_bw, max_rate);
435 	MLX5_SET(scheduling_context, tsar_ctx, bw_share, bw_share);
436 	attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes);
437 	MLX5_SET(tsar_element, attr, tsar_type, TSAR_ELEMENT_TSAR_TYPE_DWRR);
438 
439 	return mlx5_create_scheduling_element_cmd(dev,
440 						  SCHEDULING_HIERARCHY_E_SWITCH,
441 						  tsar_ctx,
442 						  tsar_ix);
443 }
444 
445 static int
esw_qos_vport_create_sched_element(struct mlx5_esw_sched_node * vport_node,struct netlink_ext_ack * extack)446 esw_qos_vport_create_sched_element(struct mlx5_esw_sched_node *vport_node,
447 				   struct netlink_ext_ack *extack)
448 {
449 	struct mlx5_esw_sched_node *parent = vport_node->parent;
450 	u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
451 	struct mlx5_core_dev *dev = vport_node->esw->dev;
452 	struct mlx5_vport *vport = vport_node->vport;
453 	void *attr;
454 
455 	if (!mlx5_qos_element_type_supported(
456 		dev,
457 		SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT,
458 		SCHEDULING_HIERARCHY_E_SWITCH))
459 		return -EOPNOTSUPP;
460 
461 	MLX5_SET(scheduling_context, sched_ctx, element_type,
462 		 SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT);
463 	attr = MLX5_ADDR_OF(scheduling_context, sched_ctx, element_attributes);
464 	MLX5_SET(vport_element, attr, vport_number, vport->vport);
465 	MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent->ix);
466 	MLX5_SET(scheduling_context, sched_ctx, max_average_bw,
467 		 vport_node->max_rate);
468 	if (vport->dev != dev) {
469 		/* The port is assigned to a node on another eswitch. */
470 		MLX5_SET(vport_element, attr, eswitch_owner_vhca_id_valid,
471 			 true);
472 		MLX5_SET(vport_element, attr, eswitch_owner_vhca_id,
473 			 MLX5_CAP_GEN(vport->dev, vhca_id));
474 	}
475 
476 	return esw_qos_node_create_sched_element(vport_node, sched_ctx, extack);
477 }
478 
479 static int
esw_qos_vport_tc_create_sched_element(struct mlx5_esw_sched_node * vport_tc_node,u32 rate_limit_elem_ix,struct netlink_ext_ack * extack)480 esw_qos_vport_tc_create_sched_element(struct mlx5_esw_sched_node *vport_tc_node,
481 				      u32 rate_limit_elem_ix,
482 				      struct netlink_ext_ack *extack)
483 {
484 	u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
485 	struct mlx5_core_dev *dev = vport_tc_node->esw->dev;
486 	struct mlx5_vport *vport = vport_tc_node->vport;
487 	void *attr;
488 
489 	if (!mlx5_qos_element_type_supported(
490 		dev,
491 		SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT_TC,
492 		SCHEDULING_HIERARCHY_E_SWITCH))
493 		return -EOPNOTSUPP;
494 
495 	MLX5_SET(scheduling_context, sched_ctx, element_type,
496 		 SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT_TC);
497 	attr = MLX5_ADDR_OF(scheduling_context, sched_ctx, element_attributes);
498 	MLX5_SET(vport_tc_element, attr, vport_number, vport->vport);
499 	MLX5_SET(vport_tc_element, attr, traffic_class, vport_tc_node->tc);
500 	MLX5_SET(scheduling_context, sched_ctx, max_bw_obj_id,
501 		 rate_limit_elem_ix);
502 	MLX5_SET(scheduling_context, sched_ctx, parent_element_id,
503 		 vport_tc_node->parent->ix);
504 	MLX5_SET(scheduling_context, sched_ctx, bw_share,
505 		 vport_tc_node->bw_share);
506 	if (vport->dev != dev) {
507 		/* The port is assigned to a node on another eswitch. */
508 		MLX5_SET(vport_tc_element, attr, eswitch_owner_vhca_id_valid,
509 			 true);
510 		MLX5_SET(vport_tc_element, attr, eswitch_owner_vhca_id,
511 			 MLX5_CAP_GEN(vport->dev, vhca_id));
512 	}
513 
514 	return esw_qos_node_create_sched_element(vport_tc_node, sched_ctx,
515 						 extack);
516 }
517 
518 static struct mlx5_esw_sched_node *
__esw_qos_alloc_node(u32 tsar_ix,enum sched_node_type type,struct mlx5_esw_sched_node * parent)519 __esw_qos_alloc_node(u32 tsar_ix, enum sched_node_type type,
520 		     struct mlx5_esw_sched_node *parent)
521 {
522 	struct mlx5_esw_sched_node *node;
523 
524 	node = kzalloc_obj(*node);
525 	if (!node)
526 		return NULL;
527 
528 	node->ix = tsar_ix;
529 	node->type = type;
530 	INIT_LIST_HEAD(&node->children);
531 	INIT_LIST_HEAD(&node->entry);
532 	if (parent)
533 		esw_qos_node_set_parent(node, parent);
534 
535 	return node;
536 }
537 
__esw_qos_free_node(struct mlx5_esw_sched_node * node)538 static void __esw_qos_free_node(struct mlx5_esw_sched_node *node)
539 {
540 	list_del(&node->entry);
541 	kfree(node);
542 }
543 
esw_qos_destroy_node(struct mlx5_esw_sched_node * node,struct netlink_ext_ack * extack)544 static void esw_qos_destroy_node(struct mlx5_esw_sched_node *node, struct netlink_ext_ack *extack)
545 {
546 	esw_qos_node_destroy_sched_element(node, extack);
547 	__esw_qos_free_node(node);
548 }
549 
esw_qos_create_vports_tc_node(struct mlx5_esw_sched_node * parent,u8 tc,struct netlink_ext_ack * extack)550 static int esw_qos_create_vports_tc_node(struct mlx5_esw_sched_node *parent,
551 					 u8 tc, struct netlink_ext_ack *extack)
552 {
553 	u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
554 	struct mlx5_core_dev *dev = parent->esw->dev;
555 	struct mlx5_esw_sched_node *vports_tc_node;
556 	void *attr;
557 	int err;
558 
559 	if (!mlx5_qos_element_type_supported(
560 		dev,
561 		SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR,
562 		SCHEDULING_HIERARCHY_E_SWITCH) ||
563 	    !mlx5_qos_tsar_type_supported(dev,
564 					  TSAR_ELEMENT_TSAR_TYPE_DWRR,
565 					  SCHEDULING_HIERARCHY_E_SWITCH))
566 		return -EOPNOTSUPP;
567 
568 	vports_tc_node = __esw_qos_alloc_node(0,
569 					      SCHED_NODE_TYPE_VPORTS_TC_TSAR,
570 					      parent);
571 	if (!vports_tc_node) {
572 		NL_SET_ERR_MSG_MOD(extack, "E-Switch alloc node failed");
573 		esw_warn(dev, "Failed to alloc vports TC node (tc=%d)\n", tc);
574 		return -ENOMEM;
575 	}
576 
577 	attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes);
578 	MLX5_SET(tsar_element, attr, tsar_type, TSAR_ELEMENT_TSAR_TYPE_DWRR);
579 	MLX5_SET(tsar_element, attr, traffic_class, tc);
580 	MLX5_SET(scheduling_context, tsar_ctx, parent_element_id, parent->ix);
581 	MLX5_SET(scheduling_context, tsar_ctx, element_type,
582 		 SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR);
583 
584 	err = esw_qos_node_create_sched_element(vports_tc_node, tsar_ctx,
585 						extack);
586 	if (err)
587 		goto err_create_sched_element;
588 
589 	vports_tc_node->tc = tc;
590 
591 	return 0;
592 
593 err_create_sched_element:
594 	__esw_qos_free_node(vports_tc_node);
595 	return err;
596 }
597 
598 static void
esw_qos_tc_arbiter_get_bw_shares(struct mlx5_esw_sched_node * tc_arbiter_node,u32 * tc_bw)599 esw_qos_tc_arbiter_get_bw_shares(struct mlx5_esw_sched_node *tc_arbiter_node,
600 				 u32 *tc_bw)
601 {
602 	memcpy(tc_bw, tc_arbiter_node->tc_bw, sizeof(tc_arbiter_node->tc_bw));
603 }
604 
605 static void
esw_qos_set_tc_arbiter_bw_shares(struct mlx5_esw_sched_node * tc_arbiter_node,u32 * tc_bw,struct netlink_ext_ack * extack)606 esw_qos_set_tc_arbiter_bw_shares(struct mlx5_esw_sched_node *tc_arbiter_node,
607 				 u32 *tc_bw, struct netlink_ext_ack *extack)
608 {
609 	struct mlx5_eswitch *esw = tc_arbiter_node->esw;
610 	struct mlx5_esw_sched_node *vports_tc_node;
611 	u32 divider, fw_max_bw_share;
612 
613 	fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
614 	divider = esw_qos_calculate_tc_bw_divider(tc_bw);
615 	list_for_each_entry(vports_tc_node, &tc_arbiter_node->children, entry) {
616 		u8 tc = vports_tc_node->tc;
617 		u32 bw_share;
618 
619 		tc_arbiter_node->tc_bw[tc] = tc_bw[tc];
620 		bw_share = tc_bw[tc] * fw_max_bw_share;
621 		bw_share = esw_qos_calc_bw_share(bw_share, divider,
622 						 fw_max_bw_share);
623 		esw_qos_sched_elem_config(vports_tc_node, 0, bw_share, extack);
624 	}
625 }
626 
627 static void
esw_qos_destroy_vports_tc_nodes(struct mlx5_esw_sched_node * tc_arbiter_node,struct netlink_ext_ack * extack)628 esw_qos_destroy_vports_tc_nodes(struct mlx5_esw_sched_node *tc_arbiter_node,
629 				struct netlink_ext_ack *extack)
630 {
631 	struct mlx5_esw_sched_node *vports_tc_node, *tmp;
632 
633 	list_for_each_entry_safe(vports_tc_node, tmp,
634 				 &tc_arbiter_node->children, entry)
635 		esw_qos_destroy_node(vports_tc_node, extack);
636 }
637 
638 static int
esw_qos_create_vports_tc_nodes(struct mlx5_esw_sched_node * tc_arbiter_node,struct netlink_ext_ack * extack)639 esw_qos_create_vports_tc_nodes(struct mlx5_esw_sched_node *tc_arbiter_node,
640 			       struct netlink_ext_ack *extack)
641 {
642 	struct mlx5_eswitch *esw = tc_arbiter_node->esw;
643 	int err, i, num_tcs = esw_qos_num_tcs(esw->dev);
644 
645 	for (i = 0; i < num_tcs; i++) {
646 		err = esw_qos_create_vports_tc_node(tc_arbiter_node, i, extack);
647 		if (err)
648 			goto err_tc_node_create;
649 	}
650 
651 	return 0;
652 
653 err_tc_node_create:
654 	esw_qos_destroy_vports_tc_nodes(tc_arbiter_node, NULL);
655 	return err;
656 }
657 
esw_qos_create_tc_arbiter_sched_elem(struct mlx5_esw_sched_node * tc_arbiter_node,struct netlink_ext_ack * extack)658 static int esw_qos_create_tc_arbiter_sched_elem(
659 		struct mlx5_esw_sched_node *tc_arbiter_node,
660 		struct netlink_ext_ack *extack)
661 {
662 	u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
663 	void *attr;
664 
665 	if (!mlx5_qos_tsar_type_supported(tc_arbiter_node->esw->dev,
666 					  TSAR_ELEMENT_TSAR_TYPE_TC_ARB,
667 					  SCHEDULING_HIERARCHY_E_SWITCH)) {
668 		NL_SET_ERR_MSG_MOD(extack,
669 				   "E-Switch TC Arbiter scheduling element is not supported");
670 		return -EOPNOTSUPP;
671 	}
672 
673 	attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes);
674 	MLX5_SET(tsar_element, attr, tsar_type, TSAR_ELEMENT_TSAR_TYPE_TC_ARB);
675 	MLX5_SET(scheduling_context, tsar_ctx, parent_element_id,
676 		 tc_arbiter_node->parent->ix);
677 	MLX5_SET(scheduling_context, tsar_ctx, element_type,
678 		 SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR);
679 	MLX5_SET(scheduling_context, tsar_ctx, max_average_bw,
680 		 tc_arbiter_node->max_rate);
681 	MLX5_SET(scheduling_context, tsar_ctx, bw_share,
682 		 tc_arbiter_node->bw_share);
683 
684 	return esw_qos_node_create_sched_element(tc_arbiter_node, tsar_ctx,
685 						 extack);
686 }
687 
688 static struct mlx5_esw_sched_node *
__esw_qos_create_vports_sched_node(struct mlx5_esw_sched_node * parent,struct netlink_ext_ack * extack)689 __esw_qos_create_vports_sched_node(struct mlx5_esw_sched_node *parent,
690 				   struct netlink_ext_ack *extack)
691 {
692 	struct mlx5_esw_sched_node *node;
693 	int err;
694 	u32 ix;
695 
696 	err = esw_qos_create_node_sched_elem(parent->esw->dev, parent->ix, 0, 0,
697 					     &ix);
698 	if (err) {
699 		NL_SET_ERR_MSG_MOD(extack, "E-Switch create TSAR for node failed");
700 		return ERR_PTR(err);
701 	}
702 
703 	node = __esw_qos_alloc_node(ix, SCHED_NODE_TYPE_VPORTS_TSAR, parent);
704 	if (!node) {
705 		NL_SET_ERR_MSG_MOD(extack, "E-Switch alloc node failed");
706 		err = -ENOMEM;
707 		goto err_alloc_node;
708 	}
709 
710 	esw_qos_normalize_min_rate(parent, extack);
711 	trace_mlx5_esw_node_qos_create(parent->esw->dev, node, node->ix);
712 
713 	return node;
714 
715 err_alloc_node:
716 	if (mlx5_destroy_scheduling_element_cmd(parent->esw->dev,
717 						SCHEDULING_HIERARCHY_E_SWITCH,
718 						ix))
719 		NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR for node failed");
720 	return ERR_PTR(err);
721 }
722 
723 static int esw_qos_get(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack);
724 static void esw_qos_put(struct mlx5_eswitch *esw);
725 
726 static struct mlx5_esw_sched_node *
esw_qos_create_vports_sched_node(struct mlx5_eswitch * esw,struct netlink_ext_ack * extack)727 esw_qos_create_vports_sched_node(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack)
728 {
729 	struct mlx5_esw_sched_node *node;
730 	int err;
731 
732 	esw_assert_qos_lock_held(esw->dev);
733 	if (!MLX5_CAP_QOS(esw->dev, log_esw_max_sched_depth))
734 		return ERR_PTR(-EOPNOTSUPP);
735 
736 	err = esw_qos_get(esw, extack);
737 	if (err)
738 		return ERR_PTR(err);
739 
740 	node = __esw_qos_create_vports_sched_node(esw->qos.root, extack);
741 	if (IS_ERR(node))
742 		esw_qos_put(esw);
743 
744 	return node;
745 }
746 
__esw_qos_destroy_node(struct mlx5_esw_sched_node * node,struct netlink_ext_ack * extack)747 static void __esw_qos_destroy_node(struct mlx5_esw_sched_node *node, struct netlink_ext_ack *extack)
748 {
749 	struct mlx5_eswitch *esw = node->esw;
750 
751 	if (node->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR)
752 		esw_qos_destroy_vports_tc_nodes(node, extack);
753 
754 	trace_mlx5_esw_node_qos_destroy(esw->dev, node, node->ix);
755 	esw_qos_destroy_node(node, extack);
756 	esw_qos_normalize_min_rate(esw->qos.root, extack);
757 }
758 
esw_qos_create(struct mlx5_eswitch * esw,struct netlink_ext_ack * extack)759 static int esw_qos_create(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack)
760 {
761 	struct mlx5_core_dev *dev = esw->dev;
762 	struct mlx5_esw_sched_node *root;
763 	u32 root_ix;
764 	int err;
765 
766 	if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
767 		return -EOPNOTSUPP;
768 
769 	err = esw_qos_create_node_sched_elem(esw->dev, 0, 0, 0, &root_ix);
770 	if (err) {
771 		esw_warn(dev, "E-Switch create root TSAR failed (%d)\n", err);
772 		return err;
773 	}
774 
775 	root = __esw_qos_alloc_node(root_ix, SCHED_NODE_TYPE_ROOT, NULL);
776 	if (!root) {
777 		esw_warn(dev, "E-Switch create root node failed\n");
778 		err = -ENOMEM;
779 		goto out_err;
780 	}
781 	root->esw = esw;
782 	root->level = 1;
783 	esw->qos.root = root;
784 	refcount_set(&esw->qos.refcnt, 1);
785 
786 	return 0;
787 out_err:
788 	mlx5_destroy_scheduling_element_cmd(dev, SCHEDULING_HIERARCHY_E_SWITCH,
789 					    root_ix);
790 	return err;
791 }
792 
esw_qos_destroy(struct mlx5_eswitch * esw)793 static void esw_qos_destroy(struct mlx5_eswitch *esw)
794 {
795 	esw_qos_destroy_node(esw->qos.root, NULL);
796 	esw->qos.root = NULL;
797 }
798 
esw_qos_get(struct mlx5_eswitch * esw,struct netlink_ext_ack * extack)799 static int esw_qos_get(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack)
800 {
801 	int err = 0;
802 
803 	esw_assert_qos_lock_held(esw->dev);
804 	if (!refcount_inc_not_zero(&esw->qos.refcnt)) {
805 		/* esw_qos_create() set refcount to 1 only on success.
806 		 * No need to decrement on failure.
807 		 */
808 		err = esw_qos_create(esw, extack);
809 	}
810 
811 	return err;
812 }
813 
esw_qos_put(struct mlx5_eswitch * esw)814 static void esw_qos_put(struct mlx5_eswitch *esw)
815 {
816 	esw_assert_qos_lock_held(esw->dev);
817 	if (refcount_dec_and_test(&esw->qos.refcnt))
818 		esw_qos_destroy(esw);
819 }
820 
821 static void
esw_qos_tc_arbiter_scheduling_teardown(struct mlx5_esw_sched_node * node,struct netlink_ext_ack * extack)822 esw_qos_tc_arbiter_scheduling_teardown(struct mlx5_esw_sched_node *node,
823 				       struct netlink_ext_ack *extack)
824 {
825 	/* Clean up all Vports TC nodes within the TC arbiter node. */
826 	esw_qos_destroy_vports_tc_nodes(node, extack);
827 	/* Destroy the scheduling element for the TC arbiter node itself. */
828 	esw_qos_node_destroy_sched_element(node, extack);
829 }
830 
esw_qos_tc_arbiter_scheduling_setup(struct mlx5_esw_sched_node * node,struct netlink_ext_ack * extack)831 static int esw_qos_tc_arbiter_scheduling_setup(struct mlx5_esw_sched_node *node,
832 					       struct netlink_ext_ack *extack)
833 {
834 	u32 curr_ix = node->ix;
835 	int err;
836 
837 	err = esw_qos_create_tc_arbiter_sched_elem(node, extack);
838 	if (err)
839 		return err;
840 	/* Initialize the vports TC nodes within created TC arbiter TSAR. */
841 	err = esw_qos_create_vports_tc_nodes(node, extack);
842 	if (err)
843 		goto err_vports_tc_nodes;
844 
845 	node->type = SCHED_NODE_TYPE_TC_ARBITER_TSAR;
846 
847 	return 0;
848 
849 err_vports_tc_nodes:
850 	/* If initialization fails, clean up the scheduling element
851 	 * for the TC arbiter node.
852 	 */
853 	esw_qos_node_destroy_sched_element(node, NULL);
854 	node->ix = curr_ix;
855 	return err;
856 }
857 
858 static int
esw_qos_create_vport_tc_sched_node(struct mlx5_vport * vport,u32 rate_limit_elem_ix,struct mlx5_esw_sched_node * vports_tc_node,struct netlink_ext_ack * extack)859 esw_qos_create_vport_tc_sched_node(struct mlx5_vport *vport,
860 				   u32 rate_limit_elem_ix,
861 				   struct mlx5_esw_sched_node *vports_tc_node,
862 				   struct netlink_ext_ack *extack)
863 {
864 	struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
865 	struct mlx5_esw_sched_node *vport_tc_node;
866 	u8 tc = vports_tc_node->tc;
867 	int err;
868 
869 	vport_tc_node = __esw_qos_alloc_node(0, SCHED_NODE_TYPE_VPORT_TC,
870 					     vports_tc_node);
871 	if (!vport_tc_node)
872 		return -ENOMEM;
873 
874 	vport_tc_node->min_rate = vport_node->min_rate;
875 	vport_tc_node->tc = tc;
876 	vport_tc_node->vport = vport;
877 	err = esw_qos_vport_tc_create_sched_element(vport_tc_node,
878 						    rate_limit_elem_ix,
879 						    extack);
880 	if (err)
881 		goto err_out;
882 
883 	vport->qos.sched_nodes[tc] = vport_tc_node;
884 
885 	return 0;
886 err_out:
887 	__esw_qos_free_node(vport_tc_node);
888 	return err;
889 }
890 
891 static void
esw_qos_destroy_vport_tc_sched_elements(struct mlx5_vport * vport,struct netlink_ext_ack * extack)892 esw_qos_destroy_vport_tc_sched_elements(struct mlx5_vport *vport,
893 					struct netlink_ext_ack *extack)
894 {
895 	int i, num_tcs = esw_qos_num_tcs(vport->qos.sched_node->esw->dev);
896 
897 	for (i = 0; i < num_tcs; i++) {
898 		if (vport->qos.sched_nodes[i]) {
899 			__esw_qos_destroy_node(vport->qos.sched_nodes[i],
900 					       extack);
901 		}
902 	}
903 
904 	kfree(vport->qos.sched_nodes);
905 	vport->qos.sched_nodes = NULL;
906 }
907 
908 static int
esw_qos_create_vport_tc_sched_elements(struct mlx5_vport * vport,enum sched_node_type type,struct netlink_ext_ack * extack)909 esw_qos_create_vport_tc_sched_elements(struct mlx5_vport *vport,
910 				       enum sched_node_type type,
911 				       struct netlink_ext_ack *extack)
912 {
913 	struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
914 	struct mlx5_esw_sched_node *tc_arbiter_node, *vports_tc_node;
915 	int err, num_tcs = esw_qos_num_tcs(vport_node->esw->dev);
916 	u32 rate_limit_elem_ix;
917 
918 	vport->qos.sched_nodes = kzalloc_objs(struct mlx5_esw_sched_node *,
919 					      num_tcs);
920 	if (!vport->qos.sched_nodes) {
921 		NL_SET_ERR_MSG_MOD(extack,
922 				   "Allocating the vport TC scheduling elements failed.");
923 		return -ENOMEM;
924 	}
925 
926 	rate_limit_elem_ix = type == SCHED_NODE_TYPE_RATE_LIMITER ?
927 			     vport_node->ix : 0;
928 	tc_arbiter_node = type == SCHED_NODE_TYPE_RATE_LIMITER ?
929 			   vport_node->parent : vport_node;
930 	list_for_each_entry(vports_tc_node, &tc_arbiter_node->children, entry) {
931 		err = esw_qos_create_vport_tc_sched_node(vport,
932 							 rate_limit_elem_ix,
933 							 vports_tc_node,
934 							 extack);
935 		if (err)
936 			goto err_create_vport_tc;
937 	}
938 
939 	return 0;
940 
941 err_create_vport_tc:
942 	esw_qos_destroy_vport_tc_sched_elements(vport, NULL);
943 
944 	return err;
945 }
946 
947 static int
esw_qos_vport_tc_enable(struct mlx5_vport * vport,enum sched_node_type type,struct netlink_ext_ack * extack)948 esw_qos_vport_tc_enable(struct mlx5_vport *vport, enum sched_node_type type,
949 			struct netlink_ext_ack *extack)
950 {
951 	struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
952 	struct mlx5_esw_sched_node *parent = vport_node->parent;
953 	int err;
954 
955 	if (type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) {
956 		int new_level, max_level;
957 
958 		/* Increase the parent's level by 2 to account for both the
959 		 * TC arbiter and the vports TC scheduling element.
960 		 */
961 		new_level = parent->level + 2;
962 		max_level = 1 << MLX5_CAP_QOS(vport_node->esw->dev,
963 					      log_esw_max_sched_depth);
964 		if (new_level > max_level) {
965 			NL_SET_ERR_MSG_FMT_MOD(extack,
966 					       "TC arbitration on leafs is not supported beyond max depth %d",
967 					       max_level);
968 			return -EOPNOTSUPP;
969 		}
970 	}
971 
972 	esw_assert_qos_lock_held(vport->dev);
973 
974 	if (type == SCHED_NODE_TYPE_RATE_LIMITER)
975 		err = esw_qos_create_rate_limit_element(vport_node, extack);
976 	else
977 		err = esw_qos_tc_arbiter_scheduling_setup(vport_node, extack);
978 	if (err)
979 		return err;
980 
981 	/* Rate limiters impact multiple nodes not directly connected to them
982 	 * and are not direct members of the QoS hierarchy.
983 	 * Unlink it from the parent to reflect that.
984 	 */
985 	if (type == SCHED_NODE_TYPE_RATE_LIMITER) {
986 		list_del_init(&vport_node->entry);
987 		vport_node->level = 0;
988 	}
989 
990 	err  = esw_qos_create_vport_tc_sched_elements(vport, type, extack);
991 	if (err)
992 		goto err_sched_nodes;
993 
994 	return 0;
995 
996 err_sched_nodes:
997 	if (type == SCHED_NODE_TYPE_RATE_LIMITER) {
998 		esw_qos_node_destroy_sched_element(vport_node, NULL);
999 		esw_qos_node_set_parent(vport_node, vport_node->parent);
1000 	} else {
1001 		esw_qos_tc_arbiter_scheduling_teardown(vport_node, NULL);
1002 	}
1003 	return err;
1004 }
1005 
esw_qos_vport_tc_disable(struct mlx5_vport * vport,struct netlink_ext_ack * extack)1006 static void esw_qos_vport_tc_disable(struct mlx5_vport *vport,
1007 				     struct netlink_ext_ack *extack)
1008 {
1009 	struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
1010 	enum sched_node_type curr_type = vport_node->type;
1011 
1012 	esw_qos_destroy_vport_tc_sched_elements(vport, extack);
1013 
1014 	if (curr_type == SCHED_NODE_TYPE_RATE_LIMITER)
1015 		esw_qos_node_destroy_sched_element(vport_node, extack);
1016 	else
1017 		esw_qos_tc_arbiter_scheduling_teardown(vport_node, extack);
1018 }
1019 
esw_qos_set_vport_tcs_min_rate(struct mlx5_vport * vport,u32 min_rate,struct netlink_ext_ack * extack)1020 static int esw_qos_set_vport_tcs_min_rate(struct mlx5_vport *vport,
1021 					  u32 min_rate,
1022 					  struct netlink_ext_ack *extack)
1023 {
1024 	struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
1025 	int err, i, num_tcs = esw_qos_num_tcs(vport_node->esw->dev);
1026 
1027 	for (i = 0; i < num_tcs; i++) {
1028 		err = esw_qos_set_node_min_rate(vport->qos.sched_nodes[i],
1029 						min_rate, extack);
1030 		if (err)
1031 			goto err_out;
1032 	}
1033 	vport_node->min_rate = min_rate;
1034 
1035 	return 0;
1036 err_out:
1037 	for (--i; i >= 0; i--) {
1038 		esw_qos_set_node_min_rate(vport->qos.sched_nodes[i],
1039 					  vport_node->min_rate, extack);
1040 	}
1041 	return err;
1042 }
1043 
esw_qos_vport_disable(struct mlx5_vport * vport,struct netlink_ext_ack * extack)1044 static void esw_qos_vport_disable(struct mlx5_vport *vport, struct netlink_ext_ack *extack)
1045 {
1046 	struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
1047 	enum sched_node_type curr_type = vport_node->type;
1048 
1049 	if (curr_type == SCHED_NODE_TYPE_VPORT)
1050 		esw_qos_node_destroy_sched_element(vport_node, extack);
1051 	else
1052 		esw_qos_vport_tc_disable(vport, extack);
1053 
1054 	vport_node->bw_share = 0;
1055 	memset(vport_node->tc_bw, 0, sizeof(vport_node->tc_bw));
1056 	list_del_init(&vport_node->entry);
1057 	esw_qos_normalize_min_rate(vport_node->parent, extack);
1058 
1059 	trace_mlx5_esw_vport_qos_destroy(vport_node->esw->dev, vport);
1060 }
1061 
esw_qos_vport_enable(struct mlx5_vport * vport,enum sched_node_type type,struct mlx5_esw_sched_node * parent,struct netlink_ext_ack * extack)1062 static int esw_qos_vport_enable(struct mlx5_vport *vport,
1063 				enum sched_node_type type,
1064 				struct mlx5_esw_sched_node *parent,
1065 				struct netlink_ext_ack *extack)
1066 {
1067 	struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
1068 	int err;
1069 
1070 	esw_assert_qos_lock_held(vport->dev);
1071 
1072 	esw_qos_node_set_parent(vport_node, parent);
1073 	if (type == SCHED_NODE_TYPE_VPORT)
1074 		err = esw_qos_vport_create_sched_element(vport_node, extack);
1075 	else
1076 		err = esw_qos_vport_tc_enable(vport, type, extack);
1077 	if (err)
1078 		return err;
1079 
1080 	vport_node->type = type;
1081 	esw_qos_normalize_min_rate(parent, extack);
1082 	trace_mlx5_esw_vport_qos_create(vport_node->esw->dev, vport,
1083 					vport_node->bw_share,
1084 					vport_node->max_rate);
1085 
1086 	return 0;
1087 }
1088 
mlx5_esw_qos_vport_enable(struct mlx5_vport * vport,enum sched_node_type type,struct mlx5_esw_sched_node * parent,u32 max_rate,u32 min_rate,struct netlink_ext_ack * extack)1089 static int mlx5_esw_qos_vport_enable(struct mlx5_vport *vport, enum sched_node_type type,
1090 				     struct mlx5_esw_sched_node *parent, u32 max_rate,
1091 				     u32 min_rate, struct netlink_ext_ack *extack)
1092 {
1093 	struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
1094 	struct mlx5_esw_sched_node *sched_node;
1095 	int err;
1096 
1097 	esw_assert_qos_lock_held(vport->dev);
1098 	err = esw_qos_get(esw, extack);
1099 	if (err)
1100 		return err;
1101 
1102 	if (!parent)
1103 		parent = esw->qos.root;
1104 	sched_node = __esw_qos_alloc_node(0, type, parent);
1105 	if (!sched_node) {
1106 		esw_qos_put(esw);
1107 		return -ENOMEM;
1108 	}
1109 
1110 	sched_node->max_rate = max_rate;
1111 	sched_node->min_rate = min_rate;
1112 	sched_node->vport = vport;
1113 	vport->qos.sched_node = sched_node;
1114 	err = esw_qos_vport_enable(vport, type, parent, extack);
1115 	if (err) {
1116 		__esw_qos_free_node(sched_node);
1117 		esw_qos_put(esw);
1118 		vport->qos.sched_node = NULL;
1119 	}
1120 
1121 	return err;
1122 }
1123 
mlx5_esw_qos_vport_disable_locked(struct mlx5_vport * vport)1124 static void mlx5_esw_qos_vport_disable_locked(struct mlx5_vport *vport)
1125 {
1126 	esw_assert_qos_lock_held(vport->dev);
1127 	if (!vport->qos.sched_node)
1128 		return;
1129 
1130 	esw_qos_vport_disable(vport, NULL);
1131 	mlx5_esw_qos_vport_qos_free(vport);
1132 	esw_qos_put(vport->dev->priv.eswitch);
1133 }
1134 
mlx5_esw_qos_vport_disable(struct mlx5_vport * vport)1135 void mlx5_esw_qos_vport_disable(struct mlx5_vport *vport)
1136 {
1137 	struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
1138 
1139 	lockdep_assert_held(&esw->state_lock);
1140 	esw_qos_shd_lock(vport->dev);
1141 	mlx5_esw_qos_vport_disable_locked(vport);
1142 	esw_qos_shd_unlock(vport->dev);
1143 }
1144 
mlx5_esw_qos_set_vport_max_rate(struct mlx5_vport * vport,u32 max_rate,struct netlink_ext_ack * extack)1145 static int mlx5_esw_qos_set_vport_max_rate(struct mlx5_vport *vport, u32 max_rate,
1146 					   struct netlink_ext_ack *extack)
1147 {
1148 	struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
1149 
1150 	esw_assert_qos_lock_held(vport->dev);
1151 
1152 	if (!vport_node)
1153 		return mlx5_esw_qos_vport_enable(vport, SCHED_NODE_TYPE_VPORT, NULL, max_rate, 0,
1154 						 extack);
1155 	else
1156 		return esw_qos_sched_elem_config(vport_node, max_rate, vport_node->bw_share,
1157 						 extack);
1158 }
1159 
mlx5_esw_qos_set_vport_min_rate(struct mlx5_vport * vport,u32 min_rate,struct netlink_ext_ack * extack)1160 static int mlx5_esw_qos_set_vport_min_rate(struct mlx5_vport *vport, u32 min_rate,
1161 					   struct netlink_ext_ack *extack)
1162 {
1163 	struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
1164 
1165 	esw_assert_qos_lock_held(vport->dev);
1166 
1167 	if (!vport_node)
1168 		return mlx5_esw_qos_vport_enable(vport, SCHED_NODE_TYPE_VPORT, NULL, 0, min_rate,
1169 						 extack);
1170 	else if (vport_node->type == SCHED_NODE_TYPE_RATE_LIMITER)
1171 		return esw_qos_set_vport_tcs_min_rate(vport, min_rate, extack);
1172 	else
1173 		return esw_qos_set_node_min_rate(vport_node, min_rate, extack);
1174 }
1175 
mlx5_esw_qos_set_vport_rate(struct mlx5_vport * vport,u32 max_rate,u32 min_rate)1176 int mlx5_esw_qos_set_vport_rate(struct mlx5_vport *vport, u32 max_rate, u32 min_rate)
1177 {
1178 	int err;
1179 
1180 	esw_qos_lock(vport->dev);
1181 	err = mlx5_esw_qos_set_vport_min_rate(vport, min_rate, NULL);
1182 	if (!err)
1183 		err = mlx5_esw_qos_set_vport_max_rate(vport, max_rate, NULL);
1184 	esw_qos_unlock(vport->dev);
1185 	return err;
1186 }
1187 
mlx5_esw_qos_get_vport_rate(struct mlx5_vport * vport,u32 * max_rate,u32 * min_rate)1188 bool mlx5_esw_qos_get_vport_rate(struct mlx5_vport *vport, u32 *max_rate, u32 *min_rate)
1189 {
1190 	bool enabled;
1191 
1192 	esw_qos_shd_lock(vport->dev);
1193 	enabled = !!vport->qos.sched_node;
1194 	if (enabled) {
1195 		*max_rate = vport->qos.sched_node->max_rate;
1196 		*min_rate = vport->qos.sched_node->min_rate;
1197 	}
1198 	esw_qos_shd_unlock(vport->dev);
1199 	return enabled;
1200 }
1201 
esw_qos_vport_tc_check_type(enum sched_node_type curr_type,enum sched_node_type new_type,struct netlink_ext_ack * extack)1202 static int esw_qos_vport_tc_check_type(enum sched_node_type curr_type,
1203 				       enum sched_node_type new_type,
1204 				       struct netlink_ext_ack *extack)
1205 {
1206 	if (curr_type == SCHED_NODE_TYPE_TC_ARBITER_TSAR &&
1207 	    new_type == SCHED_NODE_TYPE_RATE_LIMITER) {
1208 		NL_SET_ERR_MSG_MOD(extack,
1209 				   "Cannot switch from vport-level TC arbitration to node-level TC arbitration");
1210 		return -EOPNOTSUPP;
1211 	}
1212 
1213 	if (curr_type == SCHED_NODE_TYPE_RATE_LIMITER &&
1214 	    new_type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) {
1215 		NL_SET_ERR_MSG_MOD(extack,
1216 				   "Cannot switch from node-level TC arbitration to vport-level TC arbitration");
1217 		return -EOPNOTSUPP;
1218 	}
1219 
1220 	return 0;
1221 }
1222 
esw_qos_validate_unsupported_tc_bw(struct mlx5_eswitch * esw,u32 * tc_bw)1223 static bool esw_qos_validate_unsupported_tc_bw(struct mlx5_eswitch *esw,
1224 					       u32 *tc_bw)
1225 {
1226 	int i, num_tcs = esw_qos_num_tcs(esw->dev);
1227 
1228 	for (i = num_tcs; i < DEVLINK_RATE_TCS_MAX; i++)
1229 		if (tc_bw[i])
1230 			return false;
1231 
1232 	return true;
1233 }
1234 
esw_qos_vport_validate_unsupported_tc_bw(struct mlx5_vport * vport,u32 * tc_bw)1235 static bool esw_qos_vport_validate_unsupported_tc_bw(struct mlx5_vport *vport,
1236 						     u32 *tc_bw)
1237 {
1238 	struct mlx5_esw_sched_node *node = vport->qos.sched_node;
1239 	struct mlx5_eswitch *esw = node ?
1240 		node->parent->esw : vport->dev->priv.eswitch;
1241 
1242 	return esw_qos_validate_unsupported_tc_bw(esw, tc_bw);
1243 }
1244 
esw_qos_vport_update(struct mlx5_vport * vport,enum sched_node_type type,struct mlx5_esw_sched_node * parent,struct netlink_ext_ack * extack)1245 static int esw_qos_vport_update(struct mlx5_vport *vport,
1246 				enum sched_node_type type,
1247 				struct mlx5_esw_sched_node *parent,
1248 				struct netlink_ext_ack *extack)
1249 {
1250 	struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
1251 	struct mlx5_esw_sched_node *curr_parent = vport_node->parent;
1252 	enum sched_node_type curr_type = vport_node->type;
1253 	u32 curr_tc_bw[DEVLINK_RATE_TCS_MAX] = {0};
1254 	int err;
1255 
1256 	esw_assert_qos_lock_held(vport->dev);
1257 	if (curr_type == type && curr_parent == parent)
1258 		return 0;
1259 
1260 	err = esw_qos_vport_tc_check_type(curr_type, type, extack);
1261 	if (err)
1262 		return err;
1263 
1264 	if (curr_type == SCHED_NODE_TYPE_TC_ARBITER_TSAR && curr_type == type) {
1265 		esw_qos_tc_arbiter_get_bw_shares(vport_node, curr_tc_bw);
1266 		if (!esw_qos_validate_unsupported_tc_bw(parent->esw,
1267 							curr_tc_bw)) {
1268 			NL_SET_ERR_MSG_MOD(extack,
1269 					   "Unsupported traffic classes on the new device");
1270 			return -EOPNOTSUPP;
1271 		}
1272 	}
1273 
1274 	esw_qos_vport_disable(vport, extack);
1275 
1276 	err = esw_qos_vport_enable(vport, type, parent, extack);
1277 	if (err) {
1278 		esw_qos_vport_enable(vport, curr_type, curr_parent, NULL);
1279 		extack = NULL;
1280 	}
1281 
1282 	if (curr_type == SCHED_NODE_TYPE_TC_ARBITER_TSAR && curr_type == type) {
1283 		esw_qos_set_tc_arbiter_bw_shares(vport_node, curr_tc_bw,
1284 						 extack);
1285 	}
1286 
1287 	return err;
1288 }
1289 
esw_qos_vport_update_parent(struct mlx5_vport * vport,struct mlx5_esw_sched_node * parent,struct netlink_ext_ack * extack)1290 static int esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent,
1291 				       struct netlink_ext_ack *extack)
1292 {
1293 	struct mlx5_esw_sched_node *curr_parent;
1294 	enum sched_node_type type;
1295 
1296 	esw_assert_qos_lock_held(vport->dev);
1297 	curr_parent = vport->qos.sched_node->parent;
1298 	if (curr_parent == parent)
1299 		return 0;
1300 
1301 	/* Set vport QoS type based on parent node type if different from
1302 	 * default QoS; otherwise, use the vport's current QoS type.
1303 	 */
1304 	if (parent->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR)
1305 		type = SCHED_NODE_TYPE_RATE_LIMITER;
1306 	else if (curr_parent->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR)
1307 		type = SCHED_NODE_TYPE_VPORT;
1308 	else
1309 		type = vport->qos.sched_node->type;
1310 
1311 	return esw_qos_vport_update(vport, type, parent, extack);
1312 }
1313 
1314 static void
esw_qos_switch_vport_tcs_to_vport(struct mlx5_esw_sched_node * tc_arbiter_node,struct mlx5_esw_sched_node * node,struct netlink_ext_ack * extack)1315 esw_qos_switch_vport_tcs_to_vport(struct mlx5_esw_sched_node *tc_arbiter_node,
1316 				  struct mlx5_esw_sched_node *node,
1317 				  struct netlink_ext_ack *extack)
1318 {
1319 	struct mlx5_esw_sched_node *vports_tc_node, *vport_tc_node, *tmp;
1320 
1321 	vports_tc_node = list_first_entry(&tc_arbiter_node->children,
1322 					  struct mlx5_esw_sched_node,
1323 					  entry);
1324 
1325 	list_for_each_entry_safe(vport_tc_node, tmp, &vports_tc_node->children,
1326 				 entry)
1327 		esw_qos_vport_update_parent(vport_tc_node->vport, node, extack);
1328 }
1329 
esw_qos_switch_tc_arbiter_node_to_vports(struct mlx5_esw_sched_node * tc_arbiter_node,struct mlx5_esw_sched_node * node,struct netlink_ext_ack * extack)1330 static int esw_qos_switch_tc_arbiter_node_to_vports(
1331 	struct mlx5_esw_sched_node *tc_arbiter_node,
1332 	struct mlx5_esw_sched_node *node,
1333 	struct netlink_ext_ack *extack)
1334 {
1335 	int err;
1336 
1337 	err = esw_qos_create_node_sched_elem(node->esw->dev, node->parent->ix,
1338 					     node->max_rate, node->bw_share,
1339 					     &node->ix);
1340 	if (err) {
1341 		NL_SET_ERR_MSG_MOD(extack,
1342 				   "Failed to create scheduling element for vports node when disabling vports TC QoS");
1343 		return err;
1344 	}
1345 
1346 	node->type = SCHED_NODE_TYPE_VPORTS_TSAR;
1347 
1348 	/* Disable TC QoS for vports in the arbiter node. */
1349 	esw_qos_switch_vport_tcs_to_vport(tc_arbiter_node, node, extack);
1350 
1351 	return 0;
1352 }
1353 
esw_qos_switch_vports_node_to_tc_arbiter(struct mlx5_esw_sched_node * node,struct mlx5_esw_sched_node * tc_arbiter_node,struct netlink_ext_ack * extack)1354 static int esw_qos_switch_vports_node_to_tc_arbiter(
1355 	struct mlx5_esw_sched_node *node,
1356 	struct mlx5_esw_sched_node *tc_arbiter_node,
1357 	struct netlink_ext_ack *extack)
1358 {
1359 	struct mlx5_esw_sched_node *vport_node, *tmp;
1360 	struct mlx5_vport *vport;
1361 	int err;
1362 
1363 	/* Enable TC QoS for each vport in the node. */
1364 	list_for_each_entry_safe(vport_node, tmp, &node->children, entry) {
1365 		vport = vport_node->vport;
1366 		err = esw_qos_vport_update_parent(vport, tc_arbiter_node,
1367 						  extack);
1368 		if  (err)
1369 			goto err_out;
1370 	}
1371 
1372 	/* Destroy the current vports node TSAR. */
1373 	err = mlx5_destroy_scheduling_element_cmd(node->esw->dev,
1374 						  SCHEDULING_HIERARCHY_E_SWITCH,
1375 						  node->ix);
1376 	if (err)
1377 		goto err_out;
1378 
1379 	return 0;
1380 err_out:
1381 	/* Restore vports back into the node if an error occurs. */
1382 	esw_qos_switch_vport_tcs_to_vport(tc_arbiter_node, node, NULL);
1383 
1384 	return err;
1385 }
1386 
1387 static struct mlx5_esw_sched_node *
esw_qos_move_node(struct mlx5_esw_sched_node * curr_node)1388 esw_qos_move_node(struct mlx5_esw_sched_node *curr_node)
1389 {
1390 	struct mlx5_esw_sched_node *new_node;
1391 
1392 	new_node = __esw_qos_alloc_node(curr_node->ix, curr_node->type,
1393 					curr_node->parent);
1394 	if (!new_node)
1395 		return ERR_PTR(-ENOMEM);
1396 
1397 	esw_qos_nodes_set_parent(&curr_node->children, new_node);
1398 	return new_node;
1399 }
1400 
esw_qos_node_disable_tc_arbitration(struct mlx5_esw_sched_node * node,struct netlink_ext_ack * extack)1401 static int esw_qos_node_disable_tc_arbitration(struct mlx5_esw_sched_node *node,
1402 					       struct netlink_ext_ack *extack)
1403 {
1404 	struct mlx5_esw_sched_node *curr_node;
1405 	int err;
1406 
1407 	if (node->type != SCHED_NODE_TYPE_TC_ARBITER_TSAR)
1408 		return 0;
1409 
1410 	/* Allocate a new rate node to hold the current state, which will allow
1411 	 * for restoring the vports back to this node after disabling TC
1412 	 * arbitration.
1413 	 */
1414 	curr_node = esw_qos_move_node(node);
1415 	if (IS_ERR(curr_node)) {
1416 		NL_SET_ERR_MSG_MOD(extack, "Failed setting up vports node");
1417 		return PTR_ERR(curr_node);
1418 	}
1419 
1420 	/* Disable TC QoS for all vports, and assign them back to the node. */
1421 	err = esw_qos_switch_tc_arbiter_node_to_vports(curr_node, node, extack);
1422 	if (err)
1423 		goto err_out;
1424 
1425 	/* Clean up the TC arbiter node after disabling TC QoS for vports. */
1426 	esw_qos_tc_arbiter_scheduling_teardown(curr_node, extack);
1427 	goto out;
1428 err_out:
1429 	esw_qos_nodes_set_parent(&curr_node->children, node);
1430 out:
1431 	__esw_qos_free_node(curr_node);
1432 	return err;
1433 }
1434 
esw_qos_node_enable_tc_arbitration(struct mlx5_esw_sched_node * node,struct netlink_ext_ack * extack)1435 static int esw_qos_node_enable_tc_arbitration(struct mlx5_esw_sched_node *node,
1436 					      struct netlink_ext_ack *extack)
1437 {
1438 	struct mlx5_esw_sched_node *curr_node, *child;
1439 	int err, new_level, max_level;
1440 
1441 	if (node->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR)
1442 		return 0;
1443 
1444 	/* Increase the hierarchy level by one to account for the additional
1445 	 * vports TC scheduling node, and verify that the new level does not
1446 	 * exceed the maximum allowed depth.
1447 	 */
1448 	new_level = node->level + 1;
1449 	max_level = 1 << MLX5_CAP_QOS(node->esw->dev, log_esw_max_sched_depth);
1450 	if (new_level > max_level) {
1451 		NL_SET_ERR_MSG_FMT_MOD(extack,
1452 				       "TC arbitration on nodes is not supported beyond max depth %d",
1453 				       max_level);
1454 		return -EOPNOTSUPP;
1455 	}
1456 
1457 	/* Ensure the node does not contain non-leaf children before assigning
1458 	 * TC bandwidth.
1459 	 */
1460 	if (!list_empty(&node->children)) {
1461 		list_for_each_entry(child, &node->children, entry) {
1462 			if (!child->vport) {
1463 				NL_SET_ERR_MSG_MOD(extack,
1464 						   "Cannot configure TC bandwidth on a node with non-leaf children");
1465 				return -EOPNOTSUPP;
1466 			}
1467 		}
1468 	}
1469 
1470 	/* Allocate a new node that will store the information of the current
1471 	 * node. This will be used later to restore the node if necessary.
1472 	 */
1473 	curr_node = esw_qos_move_node(node);
1474 	if (IS_ERR(curr_node)) {
1475 		NL_SET_ERR_MSG_MOD(extack, "Failed setting up node TC QoS");
1476 		return PTR_ERR(curr_node);
1477 	}
1478 
1479 	/* Initialize the TC arbiter node for QoS management.
1480 	 * This step prepares the node for handling Traffic Class arbitration.
1481 	 */
1482 	err = esw_qos_tc_arbiter_scheduling_setup(node, extack);
1483 	if (err)
1484 		goto err_setup;
1485 
1486 	/* Enable TC QoS for each vport within the current node. */
1487 	err = esw_qos_switch_vports_node_to_tc_arbiter(curr_node, node, extack);
1488 	if (err)
1489 		goto err_switch_vports;
1490 	goto out;
1491 
1492 err_switch_vports:
1493 	esw_qos_tc_arbiter_scheduling_teardown(node, NULL);
1494 	node->ix = curr_node->ix;
1495 	node->type = curr_node->type;
1496 err_setup:
1497 	esw_qos_nodes_set_parent(&curr_node->children, node);
1498 out:
1499 	__esw_qos_free_node(curr_node);
1500 	return err;
1501 }
1502 
mlx5_esw_qos_max_link_speed_get(struct mlx5_core_dev * mdev,u32 * link_speed_max,struct netlink_ext_ack * extack)1503 static int mlx5_esw_qos_max_link_speed_get(struct mlx5_core_dev *mdev, u32 *link_speed_max,
1504 					   struct netlink_ext_ack *extack)
1505 {
1506 	int err;
1507 
1508 	if (!mlx5_lag_is_active(mdev) ||
1509 	    mlx5_lag_query_bond_speed(mdev, link_speed_max) < 0 ||
1510 	    *link_speed_max == 0)
1511 		goto skip_lag;
1512 
1513 	if (*link_speed_max != (u32)SPEED_UNKNOWN)
1514 		return 0;
1515 
1516 skip_lag:
1517 	err = mlx5_port_max_linkspeed(mdev, link_speed_max);
1518 	if (err)
1519 		NL_SET_ERR_MSG_MOD(extack, "Failed to get link maximum speed");
1520 
1521 	return err;
1522 }
1523 
mlx5_esw_qos_link_speed_verify(struct mlx5_core_dev * mdev,const char * name,u32 link_speed_max,u64 value,struct netlink_ext_ack * extack)1524 static int mlx5_esw_qos_link_speed_verify(struct mlx5_core_dev *mdev,
1525 					  const char *name, u32 link_speed_max,
1526 					  u64 value, struct netlink_ext_ack *extack)
1527 {
1528 	if (value > link_speed_max) {
1529 		pr_err("%s rate value %lluMbps exceed link maximum speed %u.\n",
1530 		       name, value, link_speed_max);
1531 		NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed");
1532 		return -EINVAL;
1533 	}
1534 
1535 	return 0;
1536 }
1537 
mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch * esw,u16 vport_num,u32 rate_mbps)1538 int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 rate_mbps)
1539 {
1540 	struct mlx5_vport *vport;
1541 	u32 link_speed_max;
1542 	int err;
1543 
1544 	vport = mlx5_eswitch_get_vport(esw, vport_num);
1545 	if (IS_ERR(vport))
1546 		return PTR_ERR(vport);
1547 
1548 	if (rate_mbps) {
1549 		err = mlx5_esw_qos_max_link_speed_get(esw->dev, &link_speed_max,
1550 						      NULL);
1551 		if (err)
1552 			return err;
1553 
1554 		err = mlx5_esw_qos_link_speed_verify(esw->dev, "Police",
1555 						     link_speed_max, rate_mbps, NULL);
1556 		if (err)
1557 			return err;
1558 	}
1559 
1560 	esw_qos_lock(vport->dev);
1561 	err = mlx5_esw_qos_set_vport_max_rate(vport, rate_mbps, NULL);
1562 	esw_qos_unlock(vport->dev);
1563 
1564 	return err;
1565 }
1566 
1567 #define MLX5_LINKSPEED_UNIT 125000 /* 1Mbps in Bps */
1568 
1569 /* Converts bytes per second value passed in a pointer into megabits per
1570  * second, rewriting last. If converted rate exceed link speed or is not a
1571  * fraction of Mbps - returns error.
1572  */
esw_qos_devlink_rate_to_mbps(struct mlx5_core_dev * mdev,const char * name,u64 * rate,struct netlink_ext_ack * extack)1573 static int esw_qos_devlink_rate_to_mbps(struct mlx5_core_dev *mdev, const char *name,
1574 					u64 *rate, struct netlink_ext_ack *extack)
1575 {
1576 	u32 link_speed_max, remainder;
1577 	u64 value;
1578 	int err;
1579 
1580 	value = div_u64_rem(*rate, MLX5_LINKSPEED_UNIT, &remainder);
1581 	if (remainder) {
1582 		pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n",
1583 		       name, *rate);
1584 		NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps");
1585 		return -EINVAL;
1586 	}
1587 
1588 	err = mlx5_esw_qos_max_link_speed_get(mdev, &link_speed_max, extack);
1589 	if (err)
1590 		return err;
1591 
1592 	err = mlx5_esw_qos_link_speed_verify(mdev, name, link_speed_max, value, extack);
1593 	if (err)
1594 		return err;
1595 
1596 	*rate = value;
1597 	return 0;
1598 }
1599 
esw_qos_tc_bw_disabled(u32 * tc_bw)1600 static bool esw_qos_tc_bw_disabled(u32 *tc_bw)
1601 {
1602 	int i;
1603 
1604 	for (i = 0; i < DEVLINK_RATE_TCS_MAX; i++) {
1605 		if (tc_bw[i])
1606 			return false;
1607 	}
1608 
1609 	return true;
1610 }
1611 
esw_vport_qos_prune_empty(struct mlx5_vport * vport)1612 static void esw_vport_qos_prune_empty(struct mlx5_vport *vport)
1613 {
1614 	struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
1615 
1616 	esw_assert_qos_lock_held(vport->dev);
1617 	if (!vport_node)
1618 		return;
1619 
1620 	if (vport_node->parent != vport_node->esw->qos.root ||
1621 	    vport_node->max_rate || vport_node->min_rate ||
1622 	    !esw_qos_tc_bw_disabled(vport_node->tc_bw))
1623 		return;
1624 
1625 	mlx5_esw_qos_vport_disable_locked(vport);
1626 }
1627 
1628 /* Eswitch devlink rate API */
1629 
mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate * rate_leaf,void * priv,u64 tx_share,struct netlink_ext_ack * extack)1630 int mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void *priv,
1631 					    u64 tx_share, struct netlink_ext_ack *extack)
1632 {
1633 	struct mlx5_vport *vport = priv;
1634 	int err;
1635 
1636 	if (!mlx5_esw_allowed(vport->dev->priv.eswitch))
1637 		return -EPERM;
1638 
1639 	err = esw_qos_devlink_rate_to_mbps(vport->dev, "tx_share", &tx_share, extack);
1640 	if (err)
1641 		return err;
1642 
1643 	esw_qos_devlink_lock(vport->dev);
1644 	err = mlx5_esw_qos_set_vport_min_rate(vport, tx_share, extack);
1645 	if (!err)
1646 		esw_vport_qos_prune_empty(vport);
1647 	esw_qos_devlink_unlock(vport->dev);
1648 	return err;
1649 }
1650 
mlx5_esw_devlink_rate_leaf_tx_max_set(struct devlink_rate * rate_leaf,void * priv,u64 tx_max,struct netlink_ext_ack * extack)1651 int mlx5_esw_devlink_rate_leaf_tx_max_set(struct devlink_rate *rate_leaf, void *priv,
1652 					  u64 tx_max, struct netlink_ext_ack *extack)
1653 {
1654 	struct mlx5_vport *vport = priv;
1655 	int err;
1656 
1657 	if (!mlx5_esw_allowed(vport->dev->priv.eswitch))
1658 		return -EPERM;
1659 
1660 	err = esw_qos_devlink_rate_to_mbps(vport->dev, "tx_max", &tx_max, extack);
1661 	if (err)
1662 		return err;
1663 
1664 	esw_qos_devlink_lock(vport->dev);
1665 	err = mlx5_esw_qos_set_vport_max_rate(vport, tx_max, extack);
1666 	if (!err)
1667 		esw_vport_qos_prune_empty(vport);
1668 	esw_qos_devlink_unlock(vport->dev);
1669 	return err;
1670 }
1671 
mlx5_esw_devlink_rate_leaf_tc_bw_set(struct devlink_rate * rate_leaf,void * priv,u32 * tc_bw,struct netlink_ext_ack * extack)1672 int mlx5_esw_devlink_rate_leaf_tc_bw_set(struct devlink_rate *rate_leaf,
1673 					 void *priv,
1674 					 u32 *tc_bw,
1675 					 struct netlink_ext_ack *extack)
1676 {
1677 	struct mlx5_esw_sched_node *vport_node;
1678 	struct mlx5_vport *vport = priv;
1679 	bool disable;
1680 	int err = 0;
1681 
1682 	if (!mlx5_esw_allowed(vport->dev->priv.eswitch))
1683 		return -EPERM;
1684 
1685 	disable = esw_qos_tc_bw_disabled(tc_bw);
1686 	esw_qos_devlink_lock(vport->dev);
1687 
1688 	if (!esw_qos_vport_validate_unsupported_tc_bw(vport, tc_bw)) {
1689 		NL_SET_ERR_MSG_MOD(extack,
1690 				   "E-Switch traffic classes number is not supported");
1691 		err = -EOPNOTSUPP;
1692 		goto unlock;
1693 	}
1694 
1695 	vport_node = vport->qos.sched_node;
1696 	if (disable && !vport_node)
1697 		goto unlock;
1698 
1699 	if (disable) {
1700 		if (vport_node->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR)
1701 			err = esw_qos_vport_update(vport, SCHED_NODE_TYPE_VPORT,
1702 						   vport_node->parent, extack);
1703 		esw_vport_qos_prune_empty(vport);
1704 		goto unlock;
1705 	}
1706 
1707 	if (!vport_node) {
1708 		err = mlx5_esw_qos_vport_enable(vport,
1709 						SCHED_NODE_TYPE_TC_ARBITER_TSAR,
1710 						NULL, 0, 0, extack);
1711 		vport_node = vport->qos.sched_node;
1712 	} else {
1713 		err = esw_qos_vport_update(vport,
1714 					   SCHED_NODE_TYPE_TC_ARBITER_TSAR,
1715 					   vport_node->parent, extack);
1716 	}
1717 	if (!err)
1718 		esw_qos_set_tc_arbiter_bw_shares(vport_node, tc_bw, extack);
1719 unlock:
1720 	esw_qos_devlink_unlock(vport->dev);
1721 	return err;
1722 }
1723 
mlx5_esw_devlink_rate_node_tc_bw_set(struct devlink_rate * rate_node,void * priv,u32 * tc_bw,struct netlink_ext_ack * extack)1724 int mlx5_esw_devlink_rate_node_tc_bw_set(struct devlink_rate *rate_node,
1725 					 void *priv,
1726 					 u32 *tc_bw,
1727 					 struct netlink_ext_ack *extack)
1728 {
1729 	struct mlx5_esw_sched_node *node = priv;
1730 	bool disable;
1731 	int err;
1732 
1733 	if (!esw_qos_validate_unsupported_tc_bw(node->esw, tc_bw)) {
1734 		NL_SET_ERR_MSG_MOD(extack,
1735 				   "E-Switch traffic classes number is not supported");
1736 		return -EOPNOTSUPP;
1737 	}
1738 
1739 	disable = esw_qos_tc_bw_disabled(tc_bw);
1740 	esw_qos_devlink_lock(node->esw->dev);
1741 	if (disable) {
1742 		err = esw_qos_node_disable_tc_arbitration(node, extack);
1743 		goto unlock;
1744 	}
1745 
1746 	err = esw_qos_node_enable_tc_arbitration(node, extack);
1747 	if (!err)
1748 		esw_qos_set_tc_arbiter_bw_shares(node, tc_bw, extack);
1749 unlock:
1750 	esw_qos_devlink_unlock(node->esw->dev);
1751 	return err;
1752 }
1753 
mlx5_esw_devlink_rate_node_tx_share_set(struct devlink_rate * rate_node,void * priv,u64 tx_share,struct netlink_ext_ack * extack)1754 int mlx5_esw_devlink_rate_node_tx_share_set(struct devlink_rate *rate_node, void *priv,
1755 					    u64 tx_share, struct netlink_ext_ack *extack)
1756 {
1757 	struct mlx5_esw_sched_node *node = priv;
1758 	struct mlx5_eswitch *esw = node->esw;
1759 	int err;
1760 
1761 	err = esw_qos_devlink_rate_to_mbps(esw->dev, "tx_share", &tx_share, extack);
1762 	if (err)
1763 		return err;
1764 
1765 	esw_qos_devlink_lock(esw->dev);
1766 	err = esw_qos_set_node_min_rate(node, tx_share, extack);
1767 	esw_qos_devlink_unlock(esw->dev);
1768 	return err;
1769 }
1770 
mlx5_esw_devlink_rate_node_tx_max_set(struct devlink_rate * rate_node,void * priv,u64 tx_max,struct netlink_ext_ack * extack)1771 int mlx5_esw_devlink_rate_node_tx_max_set(struct devlink_rate *rate_node, void *priv,
1772 					  u64 tx_max, struct netlink_ext_ack *extack)
1773 {
1774 	struct mlx5_esw_sched_node *node = priv;
1775 	struct mlx5_eswitch *esw = node->esw;
1776 	int err;
1777 
1778 	err = esw_qos_devlink_rate_to_mbps(esw->dev, "tx_max", &tx_max, extack);
1779 	if (err)
1780 		return err;
1781 
1782 	esw_qos_devlink_lock(esw->dev);
1783 	err = esw_qos_sched_elem_config(node, tx_max, node->bw_share, extack);
1784 	esw_qos_devlink_unlock(esw->dev);
1785 	return err;
1786 }
1787 
mlx5_esw_devlink_rate_node_new(struct devlink_rate * rate_node,void ** priv,struct netlink_ext_ack * extack)1788 int mlx5_esw_devlink_rate_node_new(struct devlink_rate *rate_node, void **priv,
1789 				   struct netlink_ext_ack *extack)
1790 {
1791 	struct mlx5_esw_sched_node *node;
1792 	struct mlx5_eswitch *esw;
1793 	int err = 0;
1794 
1795 	esw = mlx5_devlink_eswitch_get(rate_node->devlink);
1796 	if (IS_ERR(esw))
1797 		return PTR_ERR(esw);
1798 
1799 	esw_qos_devlink_lock(esw->dev);
1800 	if (esw->mode != MLX5_ESWITCH_OFFLOADS) {
1801 		NL_SET_ERR_MSG_MOD(extack,
1802 				   "Rate node creation supported only in switchdev mode");
1803 		err = -EOPNOTSUPP;
1804 		goto unlock;
1805 	}
1806 
1807 	node = esw_qos_create_vports_sched_node(esw, extack);
1808 	if (IS_ERR(node)) {
1809 		err = PTR_ERR(node);
1810 		goto unlock;
1811 	}
1812 	*priv = node;
1813 unlock:
1814 	esw_qos_devlink_unlock(esw->dev);
1815 	return err;
1816 }
1817 
mlx5_esw_devlink_rate_node_del(struct devlink_rate * rate_node,void * priv,struct netlink_ext_ack * extack)1818 int mlx5_esw_devlink_rate_node_del(struct devlink_rate *rate_node, void *priv,
1819 				   struct netlink_ext_ack *extack)
1820 {
1821 	struct mlx5_esw_sched_node *node = priv;
1822 	struct mlx5_eswitch *esw = node->esw;
1823 
1824 	esw_qos_devlink_lock(esw->dev);
1825 	__esw_qos_destroy_node(node, extack);
1826 	esw_qos_put(esw);
1827 	esw_qos_devlink_unlock(esw->dev);
1828 
1829 	return 0;
1830 }
1831 
1832 static int
mlx5_esw_validate_cross_esw_scheduling(struct mlx5_eswitch * esw,struct mlx5_esw_sched_node * parent,struct netlink_ext_ack * extack)1833 mlx5_esw_validate_cross_esw_scheduling(struct mlx5_eswitch *esw,
1834 				       struct mlx5_esw_sched_node *parent,
1835 				       struct netlink_ext_ack *extack)
1836 {
1837 	if (!parent || esw == parent->esw)
1838 		return 0;
1839 
1840 	if (!MLX5_CAP_QOS(esw->dev, esw_cross_esw_sched)) {
1841 		NL_SET_ERR_MSG_MOD(extack,
1842 				   "Cross E-Switch scheduling is not supported");
1843 		return -EOPNOTSUPP;
1844 	}
1845 	if (!esw->dev->shd || esw->dev->shd != parent->esw->dev->shd) {
1846 		NL_SET_ERR_MSG_MOD(extack,
1847 				   "Cannot add vport to a parent belonging to a different device");
1848 		return -EOPNOTSUPP;
1849 	}
1850 	if (!mlx5_lag_is_active(esw->dev)) {
1851 		NL_SET_ERR_MSG_MOD(extack,
1852 				   "Cross E-Switch scheduling requires LAG to be activated");
1853 		return -EOPNOTSUPP;
1854 	}
1855 
1856 	return 0;
1857 }
1858 
1859 static int
mlx5_esw_qos_vport_update_parent(struct mlx5_vport * vport,struct mlx5_esw_sched_node * parent,struct netlink_ext_ack * extack)1860 mlx5_esw_qos_vport_update_parent(struct mlx5_vport *vport,
1861 				 struct mlx5_esw_sched_node *parent,
1862 				 struct netlink_ext_ack *extack)
1863 {
1864 	struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
1865 	int err;
1866 
1867 	err = mlx5_esw_validate_cross_esw_scheduling(esw, parent, extack);
1868 	if (err)
1869 		return err;
1870 
1871 	if (!vport->qos.sched_node && parent) {
1872 		enum sched_node_type type;
1873 
1874 		type = parent->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR ?
1875 		       SCHED_NODE_TYPE_RATE_LIMITER : SCHED_NODE_TYPE_VPORT;
1876 		err = mlx5_esw_qos_vport_enable(vport, type, parent, 0, 0,
1877 						extack);
1878 	} else if (vport->qos.sched_node) {
1879 		err = esw_qos_vport_update_parent(vport,
1880 						  parent ? : esw->qos.root,
1881 						  extack);
1882 	}
1883 
1884 	return err;
1885 }
1886 
mlx5_esw_devlink_rate_leaf_parent_set(struct devlink_rate * devlink_rate,struct devlink_rate * parent,void * priv,void * parent_priv,struct netlink_ext_ack * extack)1887 int mlx5_esw_devlink_rate_leaf_parent_set(struct devlink_rate *devlink_rate,
1888 					  struct devlink_rate *parent,
1889 					  void *priv, void *parent_priv,
1890 					  struct netlink_ext_ack *extack)
1891 {
1892 	struct mlx5_esw_sched_node *node = parent ? parent_priv : NULL;
1893 	struct mlx5_vport *vport = priv;
1894 	int err;
1895 
1896 	esw_qos_devlink_lock(vport->dev);
1897 	err = mlx5_esw_qos_vport_update_parent(vport, node, extack);
1898 	if (!err)
1899 		esw_vport_qos_prune_empty(vport);
1900 	esw_qos_devlink_unlock(vport->dev);
1901 
1902 	return err;
1903 }
1904 
esw_qos_is_node_empty(struct mlx5_esw_sched_node * node)1905 static bool esw_qos_is_node_empty(struct mlx5_esw_sched_node *node)
1906 {
1907 	if (list_empty(&node->children))
1908 		return true;
1909 
1910 	if (node->type != SCHED_NODE_TYPE_TC_ARBITER_TSAR)
1911 		return false;
1912 
1913 	node = list_first_entry(&node->children, struct mlx5_esw_sched_node,
1914 				entry);
1915 
1916 	return esw_qos_is_node_empty(node);
1917 }
1918 
1919 static int
mlx5_esw_qos_node_validate_set_parent(struct mlx5_esw_sched_node * node,struct mlx5_esw_sched_node * parent,struct netlink_ext_ack * extack)1920 mlx5_esw_qos_node_validate_set_parent(struct mlx5_esw_sched_node *node,
1921 				      struct mlx5_esw_sched_node *parent,
1922 				      struct netlink_ext_ack *extack)
1923 {
1924 	u8 new_level, max_level;
1925 
1926 	if (parent->esw != node->esw) {
1927 		NL_SET_ERR_MSG_MOD(extack,
1928 				   "Cannot assign node to another E-Switch");
1929 		return -EOPNOTSUPP;
1930 	}
1931 
1932 	if (!esw_qos_is_node_empty(node)) {
1933 		NL_SET_ERR_MSG_MOD(extack,
1934 				   "Cannot reassign a node that contains rate objects");
1935 		return -EOPNOTSUPP;
1936 	}
1937 
1938 	if (parent->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) {
1939 		NL_SET_ERR_MSG_MOD(extack,
1940 				   "Cannot attach a node to a parent with TC bandwidth configured");
1941 		return -EOPNOTSUPP;
1942 	}
1943 
1944 	new_level = parent->level + 1;
1945 	if (node->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) {
1946 		/* Increase by one to account for the vports TC scheduling
1947 		 * element.
1948 		 */
1949 		new_level += 1;
1950 	}
1951 
1952 	max_level = 1 << MLX5_CAP_QOS(node->esw->dev, log_esw_max_sched_depth);
1953 	if (new_level > max_level) {
1954 		NL_SET_ERR_MSG_FMT_MOD(extack,
1955 				       "Node hierarchy depth %d exceeds the maximum supported level %d",
1956 				       new_level, max_level);
1957 		return -EOPNOTSUPP;
1958 	}
1959 
1960 	return 0;
1961 }
1962 
1963 static int
esw_qos_tc_arbiter_node_update_parent(struct mlx5_esw_sched_node * node,struct mlx5_esw_sched_node * parent,struct netlink_ext_ack * extack)1964 esw_qos_tc_arbiter_node_update_parent(struct mlx5_esw_sched_node *node,
1965 				      struct mlx5_esw_sched_node *parent,
1966 				      struct netlink_ext_ack *extack)
1967 {
1968 	struct mlx5_esw_sched_node *curr_parent = node->parent;
1969 	u32 curr_tc_bw[DEVLINK_RATE_TCS_MAX] = {0};
1970 	struct mlx5_eswitch *esw = node->esw;
1971 	int err;
1972 
1973 	esw_qos_tc_arbiter_get_bw_shares(node, curr_tc_bw);
1974 	esw_qos_tc_arbiter_scheduling_teardown(node, extack);
1975 	esw_qos_node_set_parent(node, parent);
1976 	err = esw_qos_tc_arbiter_scheduling_setup(node, extack);
1977 	if (err) {
1978 		esw_qos_node_set_parent(node, curr_parent);
1979 		if (esw_qos_tc_arbiter_scheduling_setup(node, extack)) {
1980 			esw_warn(esw->dev, "Node restore QoS failed\n");
1981 			return err;
1982 		}
1983 	}
1984 	esw_qos_set_tc_arbiter_bw_shares(node, curr_tc_bw, extack);
1985 
1986 	return err;
1987 }
1988 
esw_qos_vports_node_update_parent(struct mlx5_esw_sched_node * node,struct mlx5_esw_sched_node * parent,struct netlink_ext_ack * extack)1989 static int esw_qos_vports_node_update_parent(struct mlx5_esw_sched_node *node,
1990 					     struct mlx5_esw_sched_node *parent,
1991 					     struct netlink_ext_ack *extack)
1992 {
1993 	struct mlx5_esw_sched_node *curr_parent = node->parent;
1994 	struct mlx5_eswitch *esw = node->esw;
1995 	int err;
1996 
1997 	mlx5_destroy_scheduling_element_cmd(esw->dev,
1998 					    SCHEDULING_HIERARCHY_E_SWITCH,
1999 					    node->ix);
2000 	err = esw_qos_create_node_sched_elem(esw->dev, parent->ix,
2001 					     node->max_rate, 0, &node->ix);
2002 	if (err) {
2003 		NL_SET_ERR_MSG_MOD(extack,
2004 				   "Failed to create a node under the new hierarchy.");
2005 		if (esw_qos_create_node_sched_elem(esw->dev, curr_parent->ix,
2006 						   node->max_rate,
2007 						   node->bw_share,
2008 						   &node->ix))
2009 			esw_warn(esw->dev, "Node restore QoS failed\n");
2010 
2011 		return err;
2012 	}
2013 	esw_qos_node_set_parent(node, parent);
2014 	node->bw_share = 0;
2015 
2016 	return 0;
2017 }
2018 
mlx5_esw_qos_node_update_parent(struct mlx5_esw_sched_node * node,struct mlx5_esw_sched_node * parent,struct netlink_ext_ack * extack)2019 static int mlx5_esw_qos_node_update_parent(struct mlx5_esw_sched_node *node,
2020 					   struct mlx5_esw_sched_node *parent,
2021 					   struct netlink_ext_ack *extack)
2022 {
2023 	struct mlx5_esw_sched_node *curr_parent;
2024 	struct mlx5_eswitch *esw = node->esw;
2025 	int err;
2026 
2027 	esw_qos_devlink_lock(esw->dev);
2028 	curr_parent = node->parent;
2029 	if (!parent)
2030 		parent = esw->qos.root;
2031 
2032 	err = mlx5_esw_qos_node_validate_set_parent(node, parent, extack);
2033 	if (err)
2034 		goto out;
2035 
2036 	if (node->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) {
2037 		err = esw_qos_tc_arbiter_node_update_parent(node, parent,
2038 							    extack);
2039 	} else {
2040 		err = esw_qos_vports_node_update_parent(node, parent, extack);
2041 	}
2042 
2043 	if (err)
2044 		goto out;
2045 
2046 	esw_qos_normalize_min_rate(curr_parent, extack);
2047 	esw_qos_normalize_min_rate(parent, extack);
2048 
2049 out:
2050 	esw_qos_devlink_unlock(esw->dev);
2051 	return err;
2052 }
2053 
mlx5_esw_devlink_rate_node_parent_set(struct devlink_rate * devlink_rate,struct devlink_rate * parent,void * priv,void * parent_priv,struct netlink_ext_ack * extack)2054 int mlx5_esw_devlink_rate_node_parent_set(struct devlink_rate *devlink_rate,
2055 					  struct devlink_rate *parent,
2056 					  void *priv, void *parent_priv,
2057 					  struct netlink_ext_ack *extack)
2058 {
2059 	struct mlx5_esw_sched_node *node = priv, *parent_node;
2060 
2061 	if (!parent)
2062 		return mlx5_esw_qos_node_update_parent(node, NULL, extack);
2063 
2064 	parent_node = parent_priv;
2065 	return mlx5_esw_qos_node_update_parent(node, parent_node, extack);
2066 }
2067