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