]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
4501e3d737f8072ab24d389269619479a03a23fe
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / mellanox / mlx5 / core / esw / qos.c
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 "esw/qos.h"
6 #include "en/port.h"
7 #define CREATE_TRACE_POINTS
8 #include "diag/qos_tracepoint.h"
9
10 /* Minimum supported BW share value by the HW is 1 Mbit/sec */
11 #define MLX5_MIN_BW_SHARE 1
12
13 #define MLX5_RATE_TO_BW_SHARE(rate, divider, limit) \
14 min_t(u32, max_t(u32, DIV_ROUND_UP(rate, divider), MLX5_MIN_BW_SHARE), limit)
15
16 struct mlx5_esw_rate_group {
17 u32 tsar_ix;
18 u32 max_rate;
19 u32 min_rate;
20 u32 bw_share;
21 struct list_head list;
22 };
23
24 static int esw_qos_tsar_config(struct mlx5_core_dev *dev, u32 *sched_ctx,
25 u32 parent_ix, u32 tsar_ix,
26 u32 max_rate, u32 bw_share)
27 {
28 u32 bitmask = 0;
29
30 if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
31 return -EOPNOTSUPP;
32
33 MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_ix);
34 MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
35 MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
36 bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
37 bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE;
38
39 return mlx5_modify_scheduling_element_cmd(dev,
40 SCHEDULING_HIERARCHY_E_SWITCH,
41 sched_ctx,
42 tsar_ix,
43 bitmask);
44 }
45
46 static int esw_qos_group_config(struct mlx5_eswitch *esw, struct mlx5_esw_rate_group *group,
47 u32 max_rate, u32 bw_share, struct netlink_ext_ack *extack)
48 {
49 u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
50 struct mlx5_core_dev *dev = esw->dev;
51 int err;
52
53 err = esw_qos_tsar_config(dev, sched_ctx,
54 esw->qos.root_tsar_ix, group->tsar_ix,
55 max_rate, bw_share);
56 if (err)
57 NL_SET_ERR_MSG_MOD(extack, "E-Switch modify group TSAR element failed");
58
59 trace_mlx5_esw_group_qos_config(dev, group, group->tsar_ix, bw_share, max_rate);
60
61 return err;
62 }
63
64 static int esw_qos_vport_config(struct mlx5_eswitch *esw,
65 struct mlx5_vport *vport,
66 u32 max_rate, u32 bw_share,
67 struct netlink_ext_ack *extack)
68 {
69 u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
70 struct mlx5_esw_rate_group *group = vport->qos.group;
71 struct mlx5_core_dev *dev = esw->dev;
72 u32 parent_tsar_ix;
73 void *vport_elem;
74 int err;
75
76 if (!vport->qos.enabled)
77 return -EIO;
78
79 parent_tsar_ix = group ? group->tsar_ix : esw->qos.root_tsar_ix;
80 MLX5_SET(scheduling_context, sched_ctx, element_type,
81 SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT);
82 vport_elem = MLX5_ADDR_OF(scheduling_context, sched_ctx,
83 element_attributes);
84 MLX5_SET(vport_element, vport_elem, vport_number, vport->vport);
85
86 err = esw_qos_tsar_config(dev, sched_ctx, parent_tsar_ix, vport->qos.esw_tsar_ix,
87 max_rate, bw_share);
88 if (err) {
89 esw_warn(esw->dev,
90 "E-Switch modify TSAR vport element failed (vport=%d,err=%d)\n",
91 vport->vport, err);
92 NL_SET_ERR_MSG_MOD(extack, "E-Switch modify TSAR vport element failed");
93 return err;
94 }
95
96 trace_mlx5_esw_vport_qos_config(vport, bw_share, max_rate);
97
98 return 0;
99 }
100
101 static u32 esw_qos_calculate_min_rate_divider(struct mlx5_eswitch *esw,
102 struct mlx5_esw_rate_group *group,
103 bool group_level)
104 {
105 u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
106 struct mlx5_vport *evport;
107 u32 max_guarantee = 0;
108 unsigned long i;
109
110 if (group_level) {
111 struct mlx5_esw_rate_group *group;
112
113 list_for_each_entry(group, &esw->qos.groups, list) {
114 if (group->min_rate < max_guarantee)
115 continue;
116 max_guarantee = group->min_rate;
117 }
118 } else {
119 mlx5_esw_for_each_vport(esw, i, evport) {
120 if (!evport->enabled || !evport->qos.enabled ||
121 evport->qos.group != group || evport->qos.min_rate < max_guarantee)
122 continue;
123 max_guarantee = evport->qos.min_rate;
124 }
125 }
126
127 if (max_guarantee)
128 return max_t(u32, max_guarantee / fw_max_bw_share, 1);
129
130 /* If vports min rate divider is 0 but their group has bw_share configured, then
131 * need to set bw_share for vports to minimal value.
132 */
133 if (!group_level && !max_guarantee && group->bw_share)
134 return 1;
135 return 0;
136 }
137
138 static u32 esw_qos_calc_bw_share(u32 min_rate, u32 divider, u32 fw_max)
139 {
140 if (divider)
141 return MLX5_RATE_TO_BW_SHARE(min_rate, divider, fw_max);
142
143 return 0;
144 }
145
146 static int esw_qos_normalize_vports_min_rate(struct mlx5_eswitch *esw,
147 struct mlx5_esw_rate_group *group,
148 struct netlink_ext_ack *extack)
149 {
150 u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
151 u32 divider = esw_qos_calculate_min_rate_divider(esw, group, false);
152 struct mlx5_vport *evport;
153 unsigned long i;
154 u32 bw_share;
155 int err;
156
157 mlx5_esw_for_each_vport(esw, i, evport) {
158 if (!evport->enabled || !evport->qos.enabled || evport->qos.group != group)
159 continue;
160 bw_share = esw_qos_calc_bw_share(evport->qos.min_rate, divider, fw_max_bw_share);
161
162 if (bw_share == evport->qos.bw_share)
163 continue;
164
165 err = esw_qos_vport_config(esw, evport, evport->qos.max_rate, bw_share, extack);
166 if (err)
167 return err;
168
169 evport->qos.bw_share = bw_share;
170 }
171
172 return 0;
173 }
174
175 static int esw_qos_normalize_groups_min_rate(struct mlx5_eswitch *esw, u32 divider,
176 struct netlink_ext_ack *extack)
177 {
178 u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
179 struct mlx5_esw_rate_group *group;
180 u32 bw_share;
181 int err;
182
183 list_for_each_entry(group, &esw->qos.groups, list) {
184 bw_share = esw_qos_calc_bw_share(group->min_rate, divider, fw_max_bw_share);
185
186 if (bw_share == group->bw_share)
187 continue;
188
189 err = esw_qos_group_config(esw, group, group->max_rate, bw_share, extack);
190 if (err)
191 return err;
192
193 group->bw_share = bw_share;
194
195 /* All the group's vports need to be set with default bw_share
196 * to enable them with QOS
197 */
198 err = esw_qos_normalize_vports_min_rate(esw, group, extack);
199
200 if (err)
201 return err;
202 }
203
204 return 0;
205 }
206
207 int mlx5_esw_qos_set_vport_min_rate(struct mlx5_eswitch *esw,
208 struct mlx5_vport *evport,
209 u32 min_rate,
210 struct netlink_ext_ack *extack)
211 {
212 u32 fw_max_bw_share, previous_min_rate;
213 bool min_rate_supported;
214 int err;
215
216 lockdep_assert_held(&esw->state_lock);
217 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
218 min_rate_supported = MLX5_CAP_QOS(esw->dev, esw_bw_share) &&
219 fw_max_bw_share >= MLX5_MIN_BW_SHARE;
220 if (min_rate && !min_rate_supported)
221 return -EOPNOTSUPP;
222 if (min_rate == evport->qos.min_rate)
223 return 0;
224
225 previous_min_rate = evport->qos.min_rate;
226 evport->qos.min_rate = min_rate;
227 err = esw_qos_normalize_vports_min_rate(esw, evport->qos.group, extack);
228 if (err)
229 evport->qos.min_rate = previous_min_rate;
230
231 return err;
232 }
233
234 int mlx5_esw_qos_set_vport_max_rate(struct mlx5_eswitch *esw,
235 struct mlx5_vport *evport,
236 u32 max_rate,
237 struct netlink_ext_ack *extack)
238 {
239 u32 act_max_rate = max_rate;
240 bool max_rate_supported;
241 int err;
242
243 lockdep_assert_held(&esw->state_lock);
244 max_rate_supported = MLX5_CAP_QOS(esw->dev, esw_rate_limit);
245
246 if (max_rate && !max_rate_supported)
247 return -EOPNOTSUPP;
248 if (max_rate == evport->qos.max_rate)
249 return 0;
250
251 /* If parent group has rate limit need to set to group
252 * value when new max rate is 0.
253 */
254 if (evport->qos.group && !max_rate)
255 act_max_rate = evport->qos.group->max_rate;
256
257 err = esw_qos_vport_config(esw, evport, act_max_rate, evport->qos.bw_share, extack);
258
259 if (!err)
260 evport->qos.max_rate = max_rate;
261
262 return err;
263 }
264
265 static int esw_qos_set_group_min_rate(struct mlx5_eswitch *esw, struct mlx5_esw_rate_group *group,
266 u32 min_rate, struct netlink_ext_ack *extack)
267 {
268 u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
269 struct mlx5_core_dev *dev = esw->dev;
270 u32 previous_min_rate, divider;
271 int err;
272
273 if (!(MLX5_CAP_QOS(dev, esw_bw_share) && fw_max_bw_share >= MLX5_MIN_BW_SHARE))
274 return -EOPNOTSUPP;
275
276 if (min_rate == group->min_rate)
277 return 0;
278
279 previous_min_rate = group->min_rate;
280 group->min_rate = min_rate;
281 divider = esw_qos_calculate_min_rate_divider(esw, group, true);
282 err = esw_qos_normalize_groups_min_rate(esw, divider, extack);
283 if (err) {
284 group->min_rate = previous_min_rate;
285 NL_SET_ERR_MSG_MOD(extack, "E-Switch group min rate setting failed");
286
287 /* Attempt restoring previous configuration */
288 divider = esw_qos_calculate_min_rate_divider(esw, group, true);
289 if (esw_qos_normalize_groups_min_rate(esw, divider, extack))
290 NL_SET_ERR_MSG_MOD(extack, "E-Switch BW share restore failed");
291 }
292
293 return err;
294 }
295
296 static int esw_qos_set_group_max_rate(struct mlx5_eswitch *esw,
297 struct mlx5_esw_rate_group *group,
298 u32 max_rate, struct netlink_ext_ack *extack)
299 {
300 struct mlx5_vport *vport;
301 unsigned long i;
302 int err;
303
304 if (group->max_rate == max_rate)
305 return 0;
306
307 err = esw_qos_group_config(esw, group, max_rate, group->bw_share, extack);
308 if (err)
309 return err;
310
311 group->max_rate = max_rate;
312
313 /* Any unlimited vports in the group should be set
314 * with the value of the group.
315 */
316 mlx5_esw_for_each_vport(esw, i, vport) {
317 if (!vport->enabled || !vport->qos.enabled ||
318 vport->qos.group != group || vport->qos.max_rate)
319 continue;
320
321 err = esw_qos_vport_config(esw, vport, max_rate, vport->qos.bw_share, extack);
322 if (err)
323 NL_SET_ERR_MSG_MOD(extack,
324 "E-Switch vport implicit rate limit setting failed");
325 }
326
327 return err;
328 }
329
330 static int esw_qos_vport_create_sched_element(struct mlx5_eswitch *esw,
331 struct mlx5_vport *vport,
332 u32 max_rate, u32 bw_share)
333 {
334 u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
335 struct mlx5_esw_rate_group *group = vport->qos.group;
336 struct mlx5_core_dev *dev = esw->dev;
337 u32 parent_tsar_ix;
338 void *vport_elem;
339 int err;
340
341 parent_tsar_ix = group ? group->tsar_ix : esw->qos.root_tsar_ix;
342 MLX5_SET(scheduling_context, sched_ctx, element_type,
343 SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT);
344 vport_elem = MLX5_ADDR_OF(scheduling_context, sched_ctx, element_attributes);
345 MLX5_SET(vport_element, vport_elem, vport_number, vport->vport);
346 MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_tsar_ix);
347 MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
348 MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
349
350 err = mlx5_create_scheduling_element_cmd(dev,
351 SCHEDULING_HIERARCHY_E_SWITCH,
352 sched_ctx,
353 &vport->qos.esw_tsar_ix);
354 if (err) {
355 esw_warn(esw->dev, "E-Switch create TSAR vport element failed (vport=%d,err=%d)\n",
356 vport->vport, err);
357 return err;
358 }
359
360 return 0;
361 }
362
363 static int esw_qos_update_group_scheduling_element(struct mlx5_eswitch *esw,
364 struct mlx5_vport *vport,
365 struct mlx5_esw_rate_group *curr_group,
366 struct mlx5_esw_rate_group *new_group,
367 struct netlink_ext_ack *extack)
368 {
369 u32 max_rate;
370 int err;
371
372 err = mlx5_destroy_scheduling_element_cmd(esw->dev,
373 SCHEDULING_HIERARCHY_E_SWITCH,
374 vport->qos.esw_tsar_ix);
375 if (err) {
376 NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR vport element failed");
377 return err;
378 }
379
380 vport->qos.group = new_group;
381 max_rate = vport->qos.max_rate ? vport->qos.max_rate : new_group->max_rate;
382
383 /* If vport is unlimited, we set the group's value.
384 * Therefore, if the group is limited it will apply to
385 * the vport as well and if not, vport will remain unlimited.
386 */
387 err = esw_qos_vport_create_sched_element(esw, vport, max_rate, vport->qos.bw_share);
388 if (err) {
389 NL_SET_ERR_MSG_MOD(extack, "E-Switch vport group set failed.");
390 goto err_sched;
391 }
392
393 return 0;
394
395 err_sched:
396 vport->qos.group = curr_group;
397 max_rate = vport->qos.max_rate ? vport->qos.max_rate : curr_group->max_rate;
398 if (esw_qos_vport_create_sched_element(esw, vport, max_rate, vport->qos.bw_share))
399 esw_warn(esw->dev, "E-Switch vport group restore failed (vport=%d)\n",
400 vport->vport);
401
402 return err;
403 }
404
405 static int esw_qos_vport_update_group(struct mlx5_eswitch *esw,
406 struct mlx5_vport *vport,
407 struct mlx5_esw_rate_group *group,
408 struct netlink_ext_ack *extack)
409 {
410 struct mlx5_esw_rate_group *new_group, *curr_group;
411 int err;
412
413 if (!vport->enabled)
414 return -EINVAL;
415
416 curr_group = vport->qos.group;
417 new_group = group ?: esw->qos.group0;
418 if (curr_group == new_group)
419 return 0;
420
421 err = esw_qos_update_group_scheduling_element(esw, vport, curr_group, new_group, extack);
422 if (err)
423 return err;
424
425 /* Recalculate bw share weights of old and new groups */
426 if (vport->qos.bw_share || new_group->bw_share) {
427 esw_qos_normalize_vports_min_rate(esw, curr_group, extack);
428 esw_qos_normalize_vports_min_rate(esw, new_group, extack);
429 }
430
431 return 0;
432 }
433
434 static struct mlx5_esw_rate_group *
435 esw_qos_create_rate_group(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack)
436 {
437 u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
438 struct mlx5_esw_rate_group *group;
439 u32 divider;
440 int err;
441
442 if (!MLX5_CAP_QOS(esw->dev, log_esw_max_sched_depth))
443 return ERR_PTR(-EOPNOTSUPP);
444
445 group = kzalloc(sizeof(*group), GFP_KERNEL);
446 if (!group)
447 return ERR_PTR(-ENOMEM);
448
449 MLX5_SET(scheduling_context, tsar_ctx, parent_element_id,
450 esw->qos.root_tsar_ix);
451 err = mlx5_create_scheduling_element_cmd(esw->dev,
452 SCHEDULING_HIERARCHY_E_SWITCH,
453 tsar_ctx,
454 &group->tsar_ix);
455 if (err) {
456 NL_SET_ERR_MSG_MOD(extack, "E-Switch create TSAR for group failed");
457 goto err_sched_elem;
458 }
459
460 list_add_tail(&group->list, &esw->qos.groups);
461
462 divider = esw_qos_calculate_min_rate_divider(esw, group, true);
463 if (divider) {
464 err = esw_qos_normalize_groups_min_rate(esw, divider, extack);
465 if (err) {
466 NL_SET_ERR_MSG_MOD(extack, "E-Switch groups normalization failed");
467 goto err_min_rate;
468 }
469 }
470 trace_mlx5_esw_group_qos_create(esw->dev, group, group->tsar_ix);
471
472 return group;
473
474 err_min_rate:
475 list_del(&group->list);
476 if (mlx5_destroy_scheduling_element_cmd(esw->dev,
477 SCHEDULING_HIERARCHY_E_SWITCH,
478 group->tsar_ix))
479 NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR for group failed");
480 err_sched_elem:
481 kfree(group);
482 return ERR_PTR(err);
483 }
484
485 static int esw_qos_destroy_rate_group(struct mlx5_eswitch *esw,
486 struct mlx5_esw_rate_group *group,
487 struct netlink_ext_ack *extack)
488 {
489 u32 divider;
490 int err;
491
492 list_del(&group->list);
493
494 divider = esw_qos_calculate_min_rate_divider(esw, NULL, true);
495 err = esw_qos_normalize_groups_min_rate(esw, divider, extack);
496 if (err)
497 NL_SET_ERR_MSG_MOD(extack, "E-Switch groups' normalization failed");
498
499 err = mlx5_destroy_scheduling_element_cmd(esw->dev,
500 SCHEDULING_HIERARCHY_E_SWITCH,
501 group->tsar_ix);
502 if (err)
503 NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR_ID failed");
504
505 trace_mlx5_esw_group_qos_destroy(esw->dev, group, group->tsar_ix);
506 kfree(group);
507 return err;
508 }
509
510 static bool esw_qos_element_type_supported(struct mlx5_core_dev *dev, int type)
511 {
512 switch (type) {
513 case SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR:
514 return MLX5_CAP_QOS(dev, esw_element_type) &
515 ELEMENT_TYPE_CAP_MASK_TASR;
516 case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT:
517 return MLX5_CAP_QOS(dev, esw_element_type) &
518 ELEMENT_TYPE_CAP_MASK_VPORT;
519 case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT_TC:
520 return MLX5_CAP_QOS(dev, esw_element_type) &
521 ELEMENT_TYPE_CAP_MASK_VPORT_TC;
522 case SCHEDULING_CONTEXT_ELEMENT_TYPE_PARA_VPORT_TC:
523 return MLX5_CAP_QOS(dev, esw_element_type) &
524 ELEMENT_TYPE_CAP_MASK_PARA_VPORT_TC;
525 }
526 return false;
527 }
528
529 void mlx5_esw_qos_create(struct mlx5_eswitch *esw)
530 {
531 u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
532 struct mlx5_core_dev *dev = esw->dev;
533 __be32 *attr;
534 int err;
535
536 if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
537 return;
538
539 if (!esw_qos_element_type_supported(dev, SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR))
540 return;
541
542 mutex_lock(&esw->state_lock);
543 if (esw->qos.enabled)
544 goto unlock;
545
546 MLX5_SET(scheduling_context, tsar_ctx, element_type,
547 SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR);
548
549 attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes);
550 *attr = cpu_to_be32(TSAR_ELEMENT_TSAR_TYPE_DWRR << 16);
551
552 err = mlx5_create_scheduling_element_cmd(dev,
553 SCHEDULING_HIERARCHY_E_SWITCH,
554 tsar_ctx,
555 &esw->qos.root_tsar_ix);
556 if (err) {
557 esw_warn(dev, "E-Switch create root TSAR failed (%d)\n", err);
558 goto unlock;
559 }
560
561 INIT_LIST_HEAD(&esw->qos.groups);
562 if (MLX5_CAP_QOS(dev, log_esw_max_sched_depth)) {
563 esw->qos.group0 = esw_qos_create_rate_group(esw, NULL);
564 if (IS_ERR(esw->qos.group0)) {
565 esw_warn(dev, "E-Switch create rate group 0 failed (%ld)\n",
566 PTR_ERR(esw->qos.group0));
567 goto err_group0;
568 }
569 }
570 esw->qos.enabled = true;
571 unlock:
572 mutex_unlock(&esw->state_lock);
573 return;
574
575 err_group0:
576 err = mlx5_destroy_scheduling_element_cmd(esw->dev,
577 SCHEDULING_HIERARCHY_E_SWITCH,
578 esw->qos.root_tsar_ix);
579 if (err)
580 esw_warn(esw->dev, "E-Switch destroy root TSAR failed (%d)\n", err);
581 mutex_unlock(&esw->state_lock);
582 }
583
584 void mlx5_esw_qos_destroy(struct mlx5_eswitch *esw)
585 {
586 struct devlink *devlink = priv_to_devlink(esw->dev);
587 int err;
588
589 devlink_rate_nodes_destroy(devlink);
590 mutex_lock(&esw->state_lock);
591 if (!esw->qos.enabled)
592 goto unlock;
593
594 if (esw->qos.group0)
595 esw_qos_destroy_rate_group(esw, esw->qos.group0, NULL);
596
597 err = mlx5_destroy_scheduling_element_cmd(esw->dev,
598 SCHEDULING_HIERARCHY_E_SWITCH,
599 esw->qos.root_tsar_ix);
600 if (err)
601 esw_warn(esw->dev, "E-Switch destroy root TSAR failed (%d)\n", err);
602
603 esw->qos.enabled = false;
604 unlock:
605 mutex_unlock(&esw->state_lock);
606 }
607
608 int mlx5_esw_qos_vport_enable(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
609 u32 max_rate, u32 bw_share)
610 {
611 int err;
612
613 lockdep_assert_held(&esw->state_lock);
614 if (!esw->qos.enabled)
615 return 0;
616
617 if (vport->qos.enabled)
618 return -EEXIST;
619
620 vport->qos.group = esw->qos.group0;
621
622 err = esw_qos_vport_create_sched_element(esw, vport, max_rate, bw_share);
623 if (!err) {
624 vport->qos.enabled = true;
625 trace_mlx5_esw_vport_qos_create(vport, bw_share, max_rate);
626 }
627
628 return err;
629 }
630
631 void mlx5_esw_qos_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
632 {
633 int err;
634
635 lockdep_assert_held(&esw->state_lock);
636 if (!esw->qos.enabled || !vport->qos.enabled)
637 return;
638 WARN(vport->qos.group && vport->qos.group != esw->qos.group0,
639 "Disabling QoS on port before detaching it from group");
640
641 err = mlx5_destroy_scheduling_element_cmd(esw->dev,
642 SCHEDULING_HIERARCHY_E_SWITCH,
643 vport->qos.esw_tsar_ix);
644 if (err)
645 esw_warn(esw->dev, "E-Switch destroy TSAR vport element failed (vport=%d,err=%d)\n",
646 vport->vport, err);
647
648 vport->qos.enabled = false;
649 trace_mlx5_esw_vport_qos_destroy(vport);
650 }
651
652 int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 rate_mbps)
653 {
654 u32 ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
655 struct mlx5_vport *vport;
656 u32 bitmask;
657
658 vport = mlx5_eswitch_get_vport(esw, vport_num);
659 if (IS_ERR(vport))
660 return PTR_ERR(vport);
661
662 if (!vport->qos.enabled)
663 return -EOPNOTSUPP;
664
665 MLX5_SET(scheduling_context, ctx, max_average_bw, rate_mbps);
666 bitmask = MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
667
668 return mlx5_modify_scheduling_element_cmd(esw->dev,
669 SCHEDULING_HIERARCHY_E_SWITCH,
670 ctx,
671 vport->qos.esw_tsar_ix,
672 bitmask);
673 }
674
675 #define MLX5_LINKSPEED_UNIT 125000 /* 1Mbps in Bps */
676
677 /* Converts bytes per second value passed in a pointer into megabits per
678 * second, rewriting last. If converted rate exceed link speed or is not a
679 * fraction of Mbps - returns error.
680 */
681 static int esw_qos_devlink_rate_to_mbps(struct mlx5_core_dev *mdev, const char *name,
682 u64 *rate, struct netlink_ext_ack *extack)
683 {
684 u32 link_speed_max, reminder;
685 u64 value;
686 int err;
687
688 err = mlx5e_port_max_linkspeed(mdev, &link_speed_max);
689 if (err) {
690 NL_SET_ERR_MSG_MOD(extack, "Failed to get link maximum speed");
691 return err;
692 }
693
694 value = div_u64_rem(*rate, MLX5_LINKSPEED_UNIT, &reminder);
695 if (reminder) {
696 pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n",
697 name, *rate);
698 NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps");
699 return -EINVAL;
700 }
701
702 if (value > link_speed_max) {
703 pr_err("%s rate value %lluMbps exceed link maximum speed %u.\n",
704 name, value, link_speed_max);
705 NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed");
706 return -EINVAL;
707 }
708
709 *rate = value;
710 return 0;
711 }
712
713 /* Eswitch devlink rate API */
714
715 int mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void *priv,
716 u64 tx_share, struct netlink_ext_ack *extack)
717 {
718 struct mlx5_vport *vport = priv;
719 struct mlx5_eswitch *esw;
720 int err;
721
722 esw = vport->dev->priv.eswitch;
723 if (!mlx5_esw_allowed(esw))
724 return -EPERM;
725
726 err = esw_qos_devlink_rate_to_mbps(vport->dev, "tx_share", &tx_share, extack);
727 if (err)
728 return err;
729
730 mutex_lock(&esw->state_lock);
731 err = mlx5_esw_qos_set_vport_min_rate(esw, vport, tx_share, extack);
732 mutex_unlock(&esw->state_lock);
733 return err;
734 }
735
736 int mlx5_esw_devlink_rate_leaf_tx_max_set(struct devlink_rate *rate_leaf, void *priv,
737 u64 tx_max, struct netlink_ext_ack *extack)
738 {
739 struct mlx5_vport *vport = priv;
740 struct mlx5_eswitch *esw;
741 int err;
742
743 esw = vport->dev->priv.eswitch;
744 if (!mlx5_esw_allowed(esw))
745 return -EPERM;
746
747 err = esw_qos_devlink_rate_to_mbps(vport->dev, "tx_max", &tx_max, extack);
748 if (err)
749 return err;
750
751 mutex_lock(&esw->state_lock);
752 err = mlx5_esw_qos_set_vport_max_rate(esw, vport, tx_max, extack);
753 mutex_unlock(&esw->state_lock);
754 return err;
755 }
756
757 int mlx5_esw_devlink_rate_node_tx_share_set(struct devlink_rate *rate_node, void *priv,
758 u64 tx_share, struct netlink_ext_ack *extack)
759 {
760 struct mlx5_core_dev *dev = devlink_priv(rate_node->devlink);
761 struct mlx5_eswitch *esw = dev->priv.eswitch;
762 struct mlx5_esw_rate_group *group = priv;
763 int err;
764
765 err = esw_qos_devlink_rate_to_mbps(dev, "tx_share", &tx_share, extack);
766 if (err)
767 return err;
768
769 mutex_lock(&esw->state_lock);
770 err = esw_qos_set_group_min_rate(esw, group, tx_share, extack);
771 mutex_unlock(&esw->state_lock);
772 return err;
773 }
774
775 int mlx5_esw_devlink_rate_node_tx_max_set(struct devlink_rate *rate_node, void *priv,
776 u64 tx_max, struct netlink_ext_ack *extack)
777 {
778 struct mlx5_core_dev *dev = devlink_priv(rate_node->devlink);
779 struct mlx5_eswitch *esw = dev->priv.eswitch;
780 struct mlx5_esw_rate_group *group = priv;
781 int err;
782
783 err = esw_qos_devlink_rate_to_mbps(dev, "tx_max", &tx_max, extack);
784 if (err)
785 return err;
786
787 mutex_lock(&esw->state_lock);
788 err = esw_qos_set_group_max_rate(esw, group, tx_max, extack);
789 mutex_unlock(&esw->state_lock);
790 return err;
791 }
792
793 int mlx5_esw_devlink_rate_node_new(struct devlink_rate *rate_node, void **priv,
794 struct netlink_ext_ack *extack)
795 {
796 struct mlx5_esw_rate_group *group;
797 struct mlx5_eswitch *esw;
798 int err = 0;
799
800 esw = mlx5_devlink_eswitch_get(rate_node->devlink);
801 if (IS_ERR(esw))
802 return PTR_ERR(esw);
803
804 mutex_lock(&esw->state_lock);
805 if (esw->mode != MLX5_ESWITCH_OFFLOADS) {
806 NL_SET_ERR_MSG_MOD(extack,
807 "Rate node creation supported only in switchdev mode");
808 err = -EOPNOTSUPP;
809 goto unlock;
810 }
811
812 group = esw_qos_create_rate_group(esw, extack);
813 if (IS_ERR(group)) {
814 err = PTR_ERR(group);
815 goto unlock;
816 }
817
818 *priv = group;
819 unlock:
820 mutex_unlock(&esw->state_lock);
821 return err;
822 }
823
824 int mlx5_esw_devlink_rate_node_del(struct devlink_rate *rate_node, void *priv,
825 struct netlink_ext_ack *extack)
826 {
827 struct mlx5_esw_rate_group *group = priv;
828 struct mlx5_eswitch *esw;
829 int err;
830
831 esw = mlx5_devlink_eswitch_get(rate_node->devlink);
832 if (IS_ERR(esw))
833 return PTR_ERR(esw);
834
835 mutex_lock(&esw->state_lock);
836 err = esw_qos_destroy_rate_group(esw, group, extack);
837 mutex_unlock(&esw->state_lock);
838 return err;
839 }
840
841 int mlx5_esw_qos_vport_update_group(struct mlx5_eswitch *esw,
842 struct mlx5_vport *vport,
843 struct mlx5_esw_rate_group *group,
844 struct netlink_ext_ack *extack)
845 {
846 int err;
847
848 mutex_lock(&esw->state_lock);
849 err = esw_qos_vport_update_group(esw, vport, group, extack);
850 mutex_unlock(&esw->state_lock);
851 return err;
852 }
853
854 int mlx5_esw_devlink_rate_parent_set(struct devlink_rate *devlink_rate,
855 struct devlink_rate *parent,
856 void *priv, void *parent_priv,
857 struct netlink_ext_ack *extack)
858 {
859 struct mlx5_esw_rate_group *group;
860 struct mlx5_vport *vport = priv;
861
862 if (!parent)
863 return mlx5_esw_qos_vport_update_group(vport->dev->priv.eswitch,
864 vport, NULL, extack);
865
866 group = parent_priv;
867 return mlx5_esw_qos_vport_update_group(vport->dev->priv.eswitch, vport, group, extack);
868 }