net/mlx5: E-switch, Add QoS tracepoints
[linux-2.6-microblaze.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) {
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         err = mlx5_destroy_scheduling_element_cmd(esw->dev,
477                                                   SCHEDULING_HIERARCHY_E_SWITCH,
478                                                   group->tsar_ix);
479         if (err)
480                 NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR for group failed");
481 err_sched_elem:
482         kfree(group);
483         return ERR_PTR(err);
484 }
485
486 static int esw_qos_destroy_rate_group(struct mlx5_eswitch *esw,
487                                       struct mlx5_esw_rate_group *group,
488                                       struct netlink_ext_ack *extack)
489 {
490         u32 divider;
491         int err;
492
493         list_del(&group->list);
494
495         divider = esw_qos_calculate_min_rate_divider(esw, NULL, true);
496         err = esw_qos_normalize_groups_min_rate(esw, divider, extack);
497         if (err)
498                 NL_SET_ERR_MSG_MOD(extack, "E-Switch groups' normalization failed");
499
500         err = mlx5_destroy_scheduling_element_cmd(esw->dev,
501                                                   SCHEDULING_HIERARCHY_E_SWITCH,
502                                                   group->tsar_ix);
503         if (err)
504                 NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR_ID failed");
505
506         trace_mlx5_esw_group_qos_destroy(esw->dev, group, group->tsar_ix);
507         kfree(group);
508         return err;
509 }
510
511 static bool esw_qos_element_type_supported(struct mlx5_core_dev *dev, int type)
512 {
513         switch (type) {
514         case SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR:
515                 return MLX5_CAP_QOS(dev, esw_element_type) &
516                        ELEMENT_TYPE_CAP_MASK_TASR;
517         case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT:
518                 return MLX5_CAP_QOS(dev, esw_element_type) &
519                        ELEMENT_TYPE_CAP_MASK_VPORT;
520         case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT_TC:
521                 return MLX5_CAP_QOS(dev, esw_element_type) &
522                        ELEMENT_TYPE_CAP_MASK_VPORT_TC;
523         case SCHEDULING_CONTEXT_ELEMENT_TYPE_PARA_VPORT_TC:
524                 return MLX5_CAP_QOS(dev, esw_element_type) &
525                        ELEMENT_TYPE_CAP_MASK_PARA_VPORT_TC;
526         }
527         return false;
528 }
529
530 void mlx5_esw_qos_create(struct mlx5_eswitch *esw)
531 {
532         u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
533         struct mlx5_core_dev *dev = esw->dev;
534         __be32 *attr;
535         int err;
536
537         if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
538                 return;
539
540         if (!esw_qos_element_type_supported(dev, SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR))
541                 return;
542
543         mutex_lock(&esw->state_lock);
544         if (esw->qos.enabled)
545                 goto unlock;
546
547         MLX5_SET(scheduling_context, tsar_ctx, element_type,
548                  SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR);
549
550         attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes);
551         *attr = cpu_to_be32(TSAR_ELEMENT_TSAR_TYPE_DWRR << 16);
552
553         err = mlx5_create_scheduling_element_cmd(dev,
554                                                  SCHEDULING_HIERARCHY_E_SWITCH,
555                                                  tsar_ctx,
556                                                  &esw->qos.root_tsar_ix);
557         if (err) {
558                 esw_warn(dev, "E-Switch create root TSAR failed (%d)\n", err);
559                 goto unlock;
560         }
561
562         INIT_LIST_HEAD(&esw->qos.groups);
563         if (MLX5_CAP_QOS(dev, log_esw_max_sched_depth)) {
564                 esw->qos.group0 = esw_qos_create_rate_group(esw, NULL);
565                 if (IS_ERR(esw->qos.group0)) {
566                         esw_warn(dev, "E-Switch create rate group 0 failed (%ld)\n",
567                                  PTR_ERR(esw->qos.group0));
568                         goto err_group0;
569                 }
570         }
571         esw->qos.enabled = true;
572 unlock:
573         mutex_unlock(&esw->state_lock);
574         return;
575
576 err_group0:
577         err = mlx5_destroy_scheduling_element_cmd(esw->dev,
578                                                   SCHEDULING_HIERARCHY_E_SWITCH,
579                                                   esw->qos.root_tsar_ix);
580         if (err)
581                 esw_warn(esw->dev, "E-Switch destroy root TSAR failed (%d)\n", err);
582         mutex_unlock(&esw->state_lock);
583 }
584
585 void mlx5_esw_qos_destroy(struct mlx5_eswitch *esw)
586 {
587         struct devlink *devlink = priv_to_devlink(esw->dev);
588         int err;
589
590         devlink_rate_nodes_destroy(devlink);
591         mutex_lock(&esw->state_lock);
592         if (!esw->qos.enabled)
593                 goto unlock;
594
595         if (esw->qos.group0)
596                 esw_qos_destroy_rate_group(esw, esw->qos.group0, NULL);
597
598         err = mlx5_destroy_scheduling_element_cmd(esw->dev,
599                                                   SCHEDULING_HIERARCHY_E_SWITCH,
600                                                   esw->qos.root_tsar_ix);
601         if (err)
602                 esw_warn(esw->dev, "E-Switch destroy root TSAR failed (%d)\n", err);
603
604         esw->qos.enabled = false;
605 unlock:
606         mutex_unlock(&esw->state_lock);
607 }
608
609 int mlx5_esw_qos_vport_enable(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
610                               u32 max_rate, u32 bw_share)
611 {
612         int err;
613
614         lockdep_assert_held(&esw->state_lock);
615         if (!esw->qos.enabled)
616                 return 0;
617
618         if (vport->qos.enabled)
619                 return -EEXIST;
620
621         vport->qos.group = esw->qos.group0;
622
623         err = esw_qos_vport_create_sched_element(esw, vport, max_rate, bw_share);
624         if (!err) {
625                 vport->qos.enabled = true;
626                 trace_mlx5_esw_vport_qos_create(vport, bw_share, max_rate);
627         }
628
629         return err;
630 }
631
632 void mlx5_esw_qos_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
633 {
634         int err;
635
636         lockdep_assert_held(&esw->state_lock);
637         if (!esw->qos.enabled || !vport->qos.enabled)
638                 return;
639         WARN(vport->qos.group && vport->qos.group != esw->qos.group0,
640              "Disabling QoS on port before detaching it from group");
641
642         err = mlx5_destroy_scheduling_element_cmd(esw->dev,
643                                                   SCHEDULING_HIERARCHY_E_SWITCH,
644                                                   vport->qos.esw_tsar_ix);
645         if (err)
646                 esw_warn(esw->dev, "E-Switch destroy TSAR vport element failed (vport=%d,err=%d)\n",
647                          vport->vport, err);
648
649         vport->qos.enabled = false;
650         trace_mlx5_esw_vport_qos_destroy(vport);
651 }
652
653 int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 rate_mbps)
654 {
655         u32 ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
656         struct mlx5_vport *vport;
657         u32 bitmask;
658
659         vport = mlx5_eswitch_get_vport(esw, vport_num);
660         if (IS_ERR(vport))
661                 return PTR_ERR(vport);
662
663         if (!vport->qos.enabled)
664                 return -EOPNOTSUPP;
665
666         MLX5_SET(scheduling_context, ctx, max_average_bw, rate_mbps);
667         bitmask = MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
668
669         return mlx5_modify_scheduling_element_cmd(esw->dev,
670                                                   SCHEDULING_HIERARCHY_E_SWITCH,
671                                                   ctx,
672                                                   vport->qos.esw_tsar_ix,
673                                                   bitmask);
674 }
675
676 #define MLX5_LINKSPEED_UNIT 125000 /* 1Mbps in Bps */
677
678 /* Converts bytes per second value passed in a pointer into megabits per
679  * second, rewriting last. If converted rate exceed link speed or is not a
680  * fraction of Mbps - returns error.
681  */
682 static int esw_qos_devlink_rate_to_mbps(struct mlx5_core_dev *mdev, const char *name,
683                                         u64 *rate, struct netlink_ext_ack *extack)
684 {
685         u32 link_speed_max, reminder;
686         u64 value;
687         int err;
688
689         err = mlx5e_port_max_linkspeed(mdev, &link_speed_max);
690         if (err) {
691                 NL_SET_ERR_MSG_MOD(extack, "Failed to get link maximum speed");
692                 return err;
693         }
694
695         value = div_u64_rem(*rate, MLX5_LINKSPEED_UNIT, &reminder);
696         if (reminder) {
697                 pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n",
698                        name, *rate);
699                 NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps");
700                 return -EINVAL;
701         }
702
703         if (value > link_speed_max) {
704                 pr_err("%s rate value %lluMbps exceed link maximum speed %u.\n",
705                        name, value, link_speed_max);
706                 NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed");
707                 return -EINVAL;
708         }
709
710         *rate = value;
711         return 0;
712 }
713
714 /* Eswitch devlink rate API */
715
716 int mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void *priv,
717                                             u64 tx_share, struct netlink_ext_ack *extack)
718 {
719         struct mlx5_vport *vport = priv;
720         struct mlx5_eswitch *esw;
721         int err;
722
723         esw = vport->dev->priv.eswitch;
724         if (!mlx5_esw_allowed(esw))
725                 return -EPERM;
726
727         err = esw_qos_devlink_rate_to_mbps(vport->dev, "tx_share", &tx_share, extack);
728         if (err)
729                 return err;
730
731         mutex_lock(&esw->state_lock);
732         err = mlx5_esw_qos_set_vport_min_rate(esw, vport, tx_share, extack);
733         mutex_unlock(&esw->state_lock);
734         return err;
735 }
736
737 int mlx5_esw_devlink_rate_leaf_tx_max_set(struct devlink_rate *rate_leaf, void *priv,
738                                           u64 tx_max, struct netlink_ext_ack *extack)
739 {
740         struct mlx5_vport *vport = priv;
741         struct mlx5_eswitch *esw;
742         int err;
743
744         esw = vport->dev->priv.eswitch;
745         if (!mlx5_esw_allowed(esw))
746                 return -EPERM;
747
748         err = esw_qos_devlink_rate_to_mbps(vport->dev, "tx_max", &tx_max, extack);
749         if (err)
750                 return err;
751
752         mutex_lock(&esw->state_lock);
753         err = mlx5_esw_qos_set_vport_max_rate(esw, vport, tx_max, extack);
754         mutex_unlock(&esw->state_lock);
755         return err;
756 }
757
758 int mlx5_esw_devlink_rate_node_tx_share_set(struct devlink_rate *rate_node, void *priv,
759                                             u64 tx_share, struct netlink_ext_ack *extack)
760 {
761         struct mlx5_core_dev *dev = devlink_priv(rate_node->devlink);
762         struct mlx5_eswitch *esw = dev->priv.eswitch;
763         struct mlx5_esw_rate_group *group = priv;
764         int err;
765
766         err = esw_qos_devlink_rate_to_mbps(dev, "tx_share", &tx_share, extack);
767         if (err)
768                 return err;
769
770         mutex_lock(&esw->state_lock);
771         err = esw_qos_set_group_min_rate(esw, group, tx_share, extack);
772         mutex_unlock(&esw->state_lock);
773         return err;
774 }
775
776 int mlx5_esw_devlink_rate_node_tx_max_set(struct devlink_rate *rate_node, void *priv,
777                                           u64 tx_max, struct netlink_ext_ack *extack)
778 {
779         struct mlx5_core_dev *dev = devlink_priv(rate_node->devlink);
780         struct mlx5_eswitch *esw = dev->priv.eswitch;
781         struct mlx5_esw_rate_group *group = priv;
782         int err;
783
784         err = esw_qos_devlink_rate_to_mbps(dev, "tx_max", &tx_max, extack);
785         if (err)
786                 return err;
787
788         mutex_lock(&esw->state_lock);
789         err = esw_qos_set_group_max_rate(esw, group, tx_max, extack);
790         mutex_unlock(&esw->state_lock);
791         return err;
792 }
793
794 int mlx5_esw_devlink_rate_node_new(struct devlink_rate *rate_node, void **priv,
795                                    struct netlink_ext_ack *extack)
796 {
797         struct mlx5_esw_rate_group *group;
798         struct mlx5_eswitch *esw;
799         int err = 0;
800
801         esw = mlx5_devlink_eswitch_get(rate_node->devlink);
802         if (IS_ERR(esw))
803                 return PTR_ERR(esw);
804
805         mutex_lock(&esw->state_lock);
806         if (esw->mode != MLX5_ESWITCH_OFFLOADS) {
807                 NL_SET_ERR_MSG_MOD(extack,
808                                    "Rate node creation supported only in switchdev mode");
809                 err = -EOPNOTSUPP;
810                 goto unlock;
811         }
812
813         group = esw_qos_create_rate_group(esw, extack);
814         if (IS_ERR(group)) {
815                 err = PTR_ERR(group);
816                 goto unlock;
817         }
818
819         *priv = group;
820 unlock:
821         mutex_unlock(&esw->state_lock);
822         return err;
823 }
824
825 int mlx5_esw_devlink_rate_node_del(struct devlink_rate *rate_node, void *priv,
826                                    struct netlink_ext_ack *extack)
827 {
828         struct mlx5_esw_rate_group *group = priv;
829         struct mlx5_eswitch *esw;
830         int err;
831
832         esw = mlx5_devlink_eswitch_get(rate_node->devlink);
833         if (IS_ERR(esw))
834                 return PTR_ERR(esw);
835
836         mutex_lock(&esw->state_lock);
837         err = esw_qos_destroy_rate_group(esw, group, extack);
838         mutex_unlock(&esw->state_lock);
839         return err;
840 }
841
842 int mlx5_esw_qos_vport_update_group(struct mlx5_eswitch *esw,
843                                     struct mlx5_vport *vport,
844                                     struct mlx5_esw_rate_group *group,
845                                     struct netlink_ext_ack *extack)
846 {
847         int err;
848
849         mutex_lock(&esw->state_lock);
850         err = esw_qos_vport_update_group(esw, vport, group, extack);
851         mutex_unlock(&esw->state_lock);
852         return err;
853 }
854
855 int mlx5_esw_devlink_rate_parent_set(struct devlink_rate *devlink_rate,
856                                      struct devlink_rate *parent,
857                                      void *priv, void *parent_priv,
858                                      struct netlink_ext_ack *extack)
859 {
860         struct mlx5_esw_rate_group *group;
861         struct mlx5_vport *vport = priv;
862
863         if (!parent)
864                 return mlx5_esw_qos_vport_update_group(vport->dev->priv.eswitch,
865                                                        vport, NULL, extack);
866
867         group = parent_priv;
868         return mlx5_esw_qos_vport_update_group(vport->dev->priv.eswitch, vport, group, extack);
869 }