Merge tag 'sched_urgent_for_v5.13_rc6' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_qdisc.c
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
3
4 #include <linux/kernel.h>
5 #include <linux/errno.h>
6 #include <linux/netdevice.h>
7 #include <net/pkt_cls.h>
8 #include <net/red.h>
9
10 #include "spectrum.h"
11 #include "spectrum_span.h"
12 #include "reg.h"
13
14 #define MLXSW_SP_PRIO_BAND_TO_TCLASS(band) (IEEE_8021QAZ_MAX_TCS - band - 1)
15 #define MLXSW_SP_PRIO_CHILD_TO_TCLASS(child) \
16         MLXSW_SP_PRIO_BAND_TO_TCLASS((child - 1))
17
18 enum mlxsw_sp_qdisc_type {
19         MLXSW_SP_QDISC_NO_QDISC,
20         MLXSW_SP_QDISC_RED,
21         MLXSW_SP_QDISC_PRIO,
22         MLXSW_SP_QDISC_ETS,
23         MLXSW_SP_QDISC_TBF,
24         MLXSW_SP_QDISC_FIFO,
25 };
26
27 struct mlxsw_sp_qdisc;
28
29 struct mlxsw_sp_qdisc_ops {
30         enum mlxsw_sp_qdisc_type type;
31         int (*check_params)(struct mlxsw_sp_port *mlxsw_sp_port,
32                             void *params);
33         int (*replace)(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
34                        struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, void *params);
35         int (*destroy)(struct mlxsw_sp_port *mlxsw_sp_port,
36                        struct mlxsw_sp_qdisc *mlxsw_sp_qdisc);
37         int (*get_stats)(struct mlxsw_sp_port *mlxsw_sp_port,
38                          struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
39                          struct tc_qopt_offload_stats *stats_ptr);
40         int (*get_xstats)(struct mlxsw_sp_port *mlxsw_sp_port,
41                           struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
42                           void *xstats_ptr);
43         void (*clean_stats)(struct mlxsw_sp_port *mlxsw_sp_port,
44                             struct mlxsw_sp_qdisc *mlxsw_sp_qdisc);
45         /* unoffload - to be used for a qdisc that stops being offloaded without
46          * being destroyed.
47          */
48         void (*unoffload)(struct mlxsw_sp_port *mlxsw_sp_port,
49                           struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, void *params);
50         struct mlxsw_sp_qdisc *(*find_class)(struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
51                                              u32 parent);
52         unsigned int num_classes;
53 };
54
55 struct mlxsw_sp_qdisc {
56         u32 handle;
57         int tclass_num;
58         u8 prio_bitmap;
59         union {
60                 struct red_stats red;
61         } xstats_base;
62         struct mlxsw_sp_qdisc_stats {
63                 u64 tx_bytes;
64                 u64 tx_packets;
65                 u64 drops;
66                 u64 overlimits;
67                 u64 backlog;
68         } stats_base;
69
70         struct mlxsw_sp_qdisc_ops *ops;
71         struct mlxsw_sp_qdisc *parent;
72         struct mlxsw_sp_qdisc *qdiscs;
73         unsigned int num_classes;
74 };
75
76 struct mlxsw_sp_qdisc_state {
77         struct mlxsw_sp_qdisc root_qdisc;
78
79         /* When a PRIO or ETS are added, the invisible FIFOs in their bands are
80          * created first. When notifications for these FIFOs arrive, it is not
81          * known what qdisc their parent handle refers to. It could be a
82          * newly-created PRIO that will replace the currently-offloaded one, or
83          * it could be e.g. a RED that will be attached below it.
84          *
85          * As the notifications start to arrive, use them to note what the
86          * future parent handle is, and keep track of which child FIFOs were
87          * seen. Then when the parent is known, retroactively offload those
88          * FIFOs.
89          */
90         u32 future_handle;
91         bool future_fifos[IEEE_8021QAZ_MAX_TCS];
92         struct mutex lock; /* Protects qdisc state. */
93 };
94
95 static bool
96 mlxsw_sp_qdisc_compare(struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, u32 handle)
97 {
98         return mlxsw_sp_qdisc->ops && mlxsw_sp_qdisc->handle == handle;
99 }
100
101 static struct mlxsw_sp_qdisc *
102 mlxsw_sp_qdisc_walk(struct mlxsw_sp_qdisc *qdisc,
103                     struct mlxsw_sp_qdisc *(*pre)(struct mlxsw_sp_qdisc *,
104                                                   void *),
105                     void *data)
106 {
107         struct mlxsw_sp_qdisc *tmp;
108         unsigned int i;
109
110         if (pre) {
111                 tmp = pre(qdisc, data);
112                 if (tmp)
113                         return tmp;
114         }
115
116         if (qdisc->ops) {
117                 for (i = 0; i < qdisc->num_classes; i++) {
118                         tmp = &qdisc->qdiscs[i];
119                         if (qdisc->ops) {
120                                 tmp = mlxsw_sp_qdisc_walk(tmp, pre, data);
121                                 if (tmp)
122                                         return tmp;
123                         }
124                 }
125         }
126
127         return NULL;
128 }
129
130 static struct mlxsw_sp_qdisc *
131 mlxsw_sp_qdisc_walk_cb_find(struct mlxsw_sp_qdisc *qdisc, void *data)
132 {
133         u32 parent = *(u32 *)data;
134
135         if (qdisc->ops && TC_H_MAJ(qdisc->handle) == TC_H_MAJ(parent)) {
136                 if (qdisc->ops->find_class)
137                         return qdisc->ops->find_class(qdisc, parent);
138         }
139
140         return NULL;
141 }
142
143 static struct mlxsw_sp_qdisc *
144 mlxsw_sp_qdisc_find(struct mlxsw_sp_port *mlxsw_sp_port, u32 parent,
145                     bool root_only)
146 {
147         struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc;
148
149         if (!qdisc_state)
150                 return NULL;
151         if (parent == TC_H_ROOT)
152                 return &qdisc_state->root_qdisc;
153         if (root_only)
154                 return NULL;
155         return mlxsw_sp_qdisc_walk(&qdisc_state->root_qdisc,
156                                    mlxsw_sp_qdisc_walk_cb_find, &parent);
157 }
158
159 static struct mlxsw_sp_qdisc *
160 mlxsw_sp_qdisc_walk_cb_find_by_handle(struct mlxsw_sp_qdisc *qdisc, void *data)
161 {
162         u32 handle = *(u32 *)data;
163
164         if (qdisc->ops && qdisc->handle == handle)
165                 return qdisc;
166         return NULL;
167 }
168
169 static struct mlxsw_sp_qdisc *
170 mlxsw_sp_qdisc_find_by_handle(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle)
171 {
172         struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc;
173
174         if (!qdisc_state)
175                 return NULL;
176         return mlxsw_sp_qdisc_walk(&qdisc_state->root_qdisc,
177                                    mlxsw_sp_qdisc_walk_cb_find_by_handle,
178                                    &handle);
179 }
180
181 static void
182 mlxsw_sp_qdisc_reduce_parent_backlog(struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
183 {
184         struct mlxsw_sp_qdisc *tmp;
185
186         for (tmp = mlxsw_sp_qdisc->parent; tmp; tmp = tmp->parent)
187                 tmp->stats_base.backlog -= mlxsw_sp_qdisc->stats_base.backlog;
188 }
189
190 static int
191 mlxsw_sp_qdisc_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
192                        struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
193 {
194         struct mlxsw_sp_qdisc *root_qdisc = &mlxsw_sp_port->qdisc->root_qdisc;
195         int err_hdroom = 0;
196         int err = 0;
197
198         if (!mlxsw_sp_qdisc)
199                 return 0;
200
201         if (root_qdisc == mlxsw_sp_qdisc) {
202                 struct mlxsw_sp_hdroom hdroom = *mlxsw_sp_port->hdroom;
203
204                 hdroom.mode = MLXSW_SP_HDROOM_MODE_DCB;
205                 mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
206                 mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
207                 mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
208                 err_hdroom = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
209         }
210
211         if (!mlxsw_sp_qdisc->ops)
212                 return 0;
213
214         mlxsw_sp_qdisc_reduce_parent_backlog(mlxsw_sp_qdisc);
215         if (mlxsw_sp_qdisc->ops->destroy)
216                 err = mlxsw_sp_qdisc->ops->destroy(mlxsw_sp_port,
217                                                    mlxsw_sp_qdisc);
218         if (mlxsw_sp_qdisc->ops->clean_stats)
219                 mlxsw_sp_qdisc->ops->clean_stats(mlxsw_sp_port, mlxsw_sp_qdisc);
220
221         mlxsw_sp_qdisc->handle = TC_H_UNSPEC;
222         mlxsw_sp_qdisc->ops = NULL;
223         mlxsw_sp_qdisc->num_classes = 0;
224         kfree(mlxsw_sp_qdisc->qdiscs);
225         mlxsw_sp_qdisc->qdiscs = NULL;
226         return err_hdroom ?: err;
227 }
228
229 static int mlxsw_sp_qdisc_create(struct mlxsw_sp_port *mlxsw_sp_port,
230                                  u32 handle,
231                                  struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
232                                  struct mlxsw_sp_qdisc_ops *ops, void *params)
233 {
234         struct mlxsw_sp_qdisc *root_qdisc = &mlxsw_sp_port->qdisc->root_qdisc;
235         struct mlxsw_sp_hdroom orig_hdroom;
236         unsigned int i;
237         int err;
238
239         err = ops->check_params(mlxsw_sp_port, params);
240         if (err)
241                 return err;
242
243         if (ops->num_classes) {
244                 mlxsw_sp_qdisc->qdiscs = kcalloc(ops->num_classes,
245                                                  sizeof(*mlxsw_sp_qdisc->qdiscs),
246                                                  GFP_KERNEL);
247                 if (!mlxsw_sp_qdisc->qdiscs)
248                         return -ENOMEM;
249
250                 for (i = 0; i < ops->num_classes; i++)
251                         mlxsw_sp_qdisc->qdiscs[i].parent = mlxsw_sp_qdisc;
252         }
253
254         orig_hdroom = *mlxsw_sp_port->hdroom;
255         if (root_qdisc == mlxsw_sp_qdisc) {
256                 struct mlxsw_sp_hdroom hdroom = orig_hdroom;
257
258                 hdroom.mode = MLXSW_SP_HDROOM_MODE_TC;
259                 mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
260                 mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
261                 mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
262
263                 err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
264                 if (err)
265                         goto err_hdroom_configure;
266         }
267
268         mlxsw_sp_qdisc->num_classes = ops->num_classes;
269         mlxsw_sp_qdisc->ops = ops;
270         mlxsw_sp_qdisc->handle = handle;
271         err = ops->replace(mlxsw_sp_port, handle, mlxsw_sp_qdisc, params);
272         if (err)
273                 goto err_replace;
274
275         return 0;
276
277 err_replace:
278         mlxsw_sp_qdisc->handle = TC_H_UNSPEC;
279         mlxsw_sp_qdisc->ops = NULL;
280         mlxsw_sp_qdisc->num_classes = 0;
281         mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
282 err_hdroom_configure:
283         kfree(mlxsw_sp_qdisc->qdiscs);
284         mlxsw_sp_qdisc->qdiscs = NULL;
285         return err;
286 }
287
288 static int
289 mlxsw_sp_qdisc_change(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
290                       struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, void *params)
291 {
292         struct mlxsw_sp_qdisc_ops *ops = mlxsw_sp_qdisc->ops;
293         int err;
294
295         err = ops->check_params(mlxsw_sp_port, params);
296         if (err)
297                 goto unoffload;
298
299         err = ops->replace(mlxsw_sp_port, handle, mlxsw_sp_qdisc, params);
300         if (err)
301                 goto unoffload;
302
303         /* Check if the Qdisc changed. That includes a situation where an
304          * invisible Qdisc replaces another one, or is being added for the
305          * first time.
306          */
307         if (mlxsw_sp_qdisc->handle != handle) {
308                 if (ops->clean_stats)
309                         ops->clean_stats(mlxsw_sp_port, mlxsw_sp_qdisc);
310         }
311
312         mlxsw_sp_qdisc->handle = handle;
313         return 0;
314
315 unoffload:
316         if (ops->unoffload)
317                 ops->unoffload(mlxsw_sp_port, mlxsw_sp_qdisc, params);
318
319         mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
320         return err;
321 }
322
323 static int
324 mlxsw_sp_qdisc_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
325                        struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
326                        struct mlxsw_sp_qdisc_ops *ops, void *params)
327 {
328         if (mlxsw_sp_qdisc->ops && mlxsw_sp_qdisc->ops->type != ops->type)
329                 /* In case this location contained a different qdisc of the
330                  * same type we can override the old qdisc configuration.
331                  * Otherwise, we need to remove the old qdisc before setting the
332                  * new one.
333                  */
334                 mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
335
336         if (!mlxsw_sp_qdisc->ops)
337                 return mlxsw_sp_qdisc_create(mlxsw_sp_port, handle,
338                                              mlxsw_sp_qdisc, ops, params);
339         else
340                 return mlxsw_sp_qdisc_change(mlxsw_sp_port, handle,
341                                              mlxsw_sp_qdisc, params);
342 }
343
344 static int
345 mlxsw_sp_qdisc_get_stats(struct mlxsw_sp_port *mlxsw_sp_port,
346                          struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
347                          struct tc_qopt_offload_stats *stats_ptr)
348 {
349         if (mlxsw_sp_qdisc && mlxsw_sp_qdisc->ops &&
350             mlxsw_sp_qdisc->ops->get_stats)
351                 return mlxsw_sp_qdisc->ops->get_stats(mlxsw_sp_port,
352                                                       mlxsw_sp_qdisc,
353                                                       stats_ptr);
354
355         return -EOPNOTSUPP;
356 }
357
358 static int
359 mlxsw_sp_qdisc_get_xstats(struct mlxsw_sp_port *mlxsw_sp_port,
360                           struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
361                           void *xstats_ptr)
362 {
363         if (mlxsw_sp_qdisc && mlxsw_sp_qdisc->ops &&
364             mlxsw_sp_qdisc->ops->get_xstats)
365                 return mlxsw_sp_qdisc->ops->get_xstats(mlxsw_sp_port,
366                                                       mlxsw_sp_qdisc,
367                                                       xstats_ptr);
368
369         return -EOPNOTSUPP;
370 }
371
372 static u64
373 mlxsw_sp_xstats_backlog(struct mlxsw_sp_port_xstats *xstats, int tclass_num)
374 {
375         return xstats->backlog[tclass_num] +
376                xstats->backlog[tclass_num + 8];
377 }
378
379 static u64
380 mlxsw_sp_xstats_tail_drop(struct mlxsw_sp_port_xstats *xstats, int tclass_num)
381 {
382         return xstats->tail_drop[tclass_num] +
383                xstats->tail_drop[tclass_num + 8];
384 }
385
386 static void
387 mlxsw_sp_qdisc_bstats_per_priority_get(struct mlxsw_sp_port_xstats *xstats,
388                                        u8 prio_bitmap, u64 *tx_packets,
389                                        u64 *tx_bytes)
390 {
391         int i;
392
393         *tx_packets = 0;
394         *tx_bytes = 0;
395         for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
396                 if (prio_bitmap & BIT(i)) {
397                         *tx_packets += xstats->tx_packets[i];
398                         *tx_bytes += xstats->tx_bytes[i];
399                 }
400         }
401 }
402
403 static void
404 mlxsw_sp_qdisc_collect_tc_stats(struct mlxsw_sp_port *mlxsw_sp_port,
405                                 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
406                                 u64 *p_tx_bytes, u64 *p_tx_packets,
407                                 u64 *p_drops, u64 *p_backlog)
408 {
409         int tclass_num = mlxsw_sp_qdisc->tclass_num;
410         struct mlxsw_sp_port_xstats *xstats;
411         u64 tx_bytes, tx_packets;
412
413         xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
414         mlxsw_sp_qdisc_bstats_per_priority_get(xstats,
415                                                mlxsw_sp_qdisc->prio_bitmap,
416                                                &tx_packets, &tx_bytes);
417
418         *p_tx_packets += tx_packets;
419         *p_tx_bytes += tx_bytes;
420         *p_drops += xstats->wred_drop[tclass_num] +
421                     mlxsw_sp_xstats_tail_drop(xstats, tclass_num);
422         *p_backlog += mlxsw_sp_xstats_backlog(xstats, tclass_num);
423 }
424
425 static void
426 mlxsw_sp_qdisc_update_stats(struct mlxsw_sp *mlxsw_sp,
427                             struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
428                             u64 tx_bytes, u64 tx_packets,
429                             u64 drops, u64 backlog,
430                             struct tc_qopt_offload_stats *stats_ptr)
431 {
432         struct mlxsw_sp_qdisc_stats *stats_base = &mlxsw_sp_qdisc->stats_base;
433
434         tx_bytes -= stats_base->tx_bytes;
435         tx_packets -= stats_base->tx_packets;
436         drops -= stats_base->drops;
437         backlog -= stats_base->backlog;
438
439         _bstats_update(stats_ptr->bstats, tx_bytes, tx_packets);
440         stats_ptr->qstats->drops += drops;
441         stats_ptr->qstats->backlog += mlxsw_sp_cells_bytes(mlxsw_sp, backlog);
442
443         stats_base->backlog += backlog;
444         stats_base->drops += drops;
445         stats_base->tx_bytes += tx_bytes;
446         stats_base->tx_packets += tx_packets;
447 }
448
449 static void
450 mlxsw_sp_qdisc_get_tc_stats(struct mlxsw_sp_port *mlxsw_sp_port,
451                             struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
452                             struct tc_qopt_offload_stats *stats_ptr)
453 {
454         u64 tx_packets = 0;
455         u64 tx_bytes = 0;
456         u64 backlog = 0;
457         u64 drops = 0;
458
459         mlxsw_sp_qdisc_collect_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
460                                         &tx_bytes, &tx_packets,
461                                         &drops, &backlog);
462         mlxsw_sp_qdisc_update_stats(mlxsw_sp_port->mlxsw_sp, mlxsw_sp_qdisc,
463                                     tx_bytes, tx_packets, drops, backlog,
464                                     stats_ptr);
465 }
466
467 static int
468 mlxsw_sp_tclass_congestion_enable(struct mlxsw_sp_port *mlxsw_sp_port,
469                                   int tclass_num, u32 min, u32 max,
470                                   u32 probability, bool is_wred, bool is_ecn)
471 {
472         char cwtpm_cmd[MLXSW_REG_CWTPM_LEN];
473         char cwtp_cmd[MLXSW_REG_CWTP_LEN];
474         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
475         int err;
476
477         mlxsw_reg_cwtp_pack(cwtp_cmd, mlxsw_sp_port->local_port, tclass_num);
478         mlxsw_reg_cwtp_profile_pack(cwtp_cmd, MLXSW_REG_CWTP_DEFAULT_PROFILE,
479                                     roundup(min, MLXSW_REG_CWTP_MIN_VALUE),
480                                     roundup(max, MLXSW_REG_CWTP_MIN_VALUE),
481                                     probability);
482
483         err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtp), cwtp_cmd);
484         if (err)
485                 return err;
486
487         mlxsw_reg_cwtpm_pack(cwtpm_cmd, mlxsw_sp_port->local_port, tclass_num,
488                              MLXSW_REG_CWTP_DEFAULT_PROFILE, is_wred, is_ecn);
489
490         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtpm), cwtpm_cmd);
491 }
492
493 static int
494 mlxsw_sp_tclass_congestion_disable(struct mlxsw_sp_port *mlxsw_sp_port,
495                                    int tclass_num)
496 {
497         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
498         char cwtpm_cmd[MLXSW_REG_CWTPM_LEN];
499
500         mlxsw_reg_cwtpm_pack(cwtpm_cmd, mlxsw_sp_port->local_port, tclass_num,
501                              MLXSW_REG_CWTPM_RESET_PROFILE, false, false);
502         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtpm), cwtpm_cmd);
503 }
504
505 static void
506 mlxsw_sp_setup_tc_qdisc_red_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
507                                         struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
508 {
509         int tclass_num = mlxsw_sp_qdisc->tclass_num;
510         struct mlxsw_sp_qdisc_stats *stats_base;
511         struct mlxsw_sp_port_xstats *xstats;
512         struct red_stats *red_base;
513
514         xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
515         stats_base = &mlxsw_sp_qdisc->stats_base;
516         red_base = &mlxsw_sp_qdisc->xstats_base.red;
517
518         mlxsw_sp_qdisc_bstats_per_priority_get(xstats,
519                                                mlxsw_sp_qdisc->prio_bitmap,
520                                                &stats_base->tx_packets,
521                                                &stats_base->tx_bytes);
522         red_base->prob_drop = xstats->wred_drop[tclass_num];
523         red_base->pdrop = mlxsw_sp_xstats_tail_drop(xstats, tclass_num);
524
525         stats_base->overlimits = red_base->prob_drop + red_base->prob_mark;
526         stats_base->drops = red_base->prob_drop + red_base->pdrop;
527
528         stats_base->backlog = 0;
529 }
530
531 static int
532 mlxsw_sp_qdisc_red_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
533                            struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
534 {
535         return mlxsw_sp_tclass_congestion_disable(mlxsw_sp_port,
536                                                   mlxsw_sp_qdisc->tclass_num);
537 }
538
539 static int
540 mlxsw_sp_qdisc_red_check_params(struct mlxsw_sp_port *mlxsw_sp_port,
541                                 void *params)
542 {
543         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
544         struct tc_red_qopt_offload_params *p = params;
545
546         if (p->min > p->max) {
547                 dev_err(mlxsw_sp->bus_info->dev,
548                         "spectrum: RED: min %u is bigger then max %u\n", p->min,
549                         p->max);
550                 return -EINVAL;
551         }
552         if (p->max > MLXSW_CORE_RES_GET(mlxsw_sp->core,
553                                         GUARANTEED_SHARED_BUFFER)) {
554                 dev_err(mlxsw_sp->bus_info->dev,
555                         "spectrum: RED: max value %u is too big\n", p->max);
556                 return -EINVAL;
557         }
558         if (p->min == 0 || p->max == 0) {
559                 dev_err(mlxsw_sp->bus_info->dev,
560                         "spectrum: RED: 0 value is illegal for min and max\n");
561                 return -EINVAL;
562         }
563         return 0;
564 }
565
566 static int
567 mlxsw_sp_qdisc_red_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
568                            struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
569                            void *params)
570 {
571         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
572         struct tc_red_qopt_offload_params *p = params;
573         int tclass_num = mlxsw_sp_qdisc->tclass_num;
574         u32 min, max;
575         u64 prob;
576
577         /* calculate probability in percentage */
578         prob = p->probability;
579         prob *= 100;
580         prob = DIV_ROUND_UP(prob, 1 << 16);
581         prob = DIV_ROUND_UP(prob, 1 << 16);
582         min = mlxsw_sp_bytes_cells(mlxsw_sp, p->min);
583         max = mlxsw_sp_bytes_cells(mlxsw_sp, p->max);
584         return mlxsw_sp_tclass_congestion_enable(mlxsw_sp_port, tclass_num,
585                                                  min, max, prob,
586                                                  !p->is_nodrop, p->is_ecn);
587 }
588
589 static void
590 mlxsw_sp_qdisc_leaf_unoffload(struct mlxsw_sp_port *mlxsw_sp_port,
591                               struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
592                               struct gnet_stats_queue *qstats)
593 {
594         u64 backlog;
595
596         backlog = mlxsw_sp_cells_bytes(mlxsw_sp_port->mlxsw_sp,
597                                        mlxsw_sp_qdisc->stats_base.backlog);
598         qstats->backlog -= backlog;
599         mlxsw_sp_qdisc->stats_base.backlog = 0;
600 }
601
602 static void
603 mlxsw_sp_qdisc_red_unoffload(struct mlxsw_sp_port *mlxsw_sp_port,
604                              struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
605                              void *params)
606 {
607         struct tc_red_qopt_offload_params *p = params;
608
609         mlxsw_sp_qdisc_leaf_unoffload(mlxsw_sp_port, mlxsw_sp_qdisc, p->qstats);
610 }
611
612 static int
613 mlxsw_sp_qdisc_get_red_xstats(struct mlxsw_sp_port *mlxsw_sp_port,
614                               struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
615                               void *xstats_ptr)
616 {
617         struct red_stats *xstats_base = &mlxsw_sp_qdisc->xstats_base.red;
618         int tclass_num = mlxsw_sp_qdisc->tclass_num;
619         struct mlxsw_sp_port_xstats *xstats;
620         struct red_stats *res = xstats_ptr;
621         int early_drops, pdrops;
622
623         xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
624
625         early_drops = xstats->wred_drop[tclass_num] - xstats_base->prob_drop;
626         pdrops = mlxsw_sp_xstats_tail_drop(xstats, tclass_num) -
627                  xstats_base->pdrop;
628
629         res->pdrop += pdrops;
630         res->prob_drop += early_drops;
631
632         xstats_base->pdrop += pdrops;
633         xstats_base->prob_drop += early_drops;
634         return 0;
635 }
636
637 static int
638 mlxsw_sp_qdisc_get_red_stats(struct mlxsw_sp_port *mlxsw_sp_port,
639                              struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
640                              struct tc_qopt_offload_stats *stats_ptr)
641 {
642         int tclass_num = mlxsw_sp_qdisc->tclass_num;
643         struct mlxsw_sp_qdisc_stats *stats_base;
644         struct mlxsw_sp_port_xstats *xstats;
645         u64 overlimits;
646
647         xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
648         stats_base = &mlxsw_sp_qdisc->stats_base;
649
650         mlxsw_sp_qdisc_get_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc, stats_ptr);
651         overlimits = xstats->wred_drop[tclass_num] - stats_base->overlimits;
652
653         stats_ptr->qstats->overlimits += overlimits;
654         stats_base->overlimits += overlimits;
655
656         return 0;
657 }
658
659 static struct mlxsw_sp_qdisc *
660 mlxsw_sp_qdisc_leaf_find_class(struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
661                                u32 parent)
662 {
663         return NULL;
664 }
665
666 #define MLXSW_SP_PORT_DEFAULT_TCLASS 0
667
668 static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_red = {
669         .type = MLXSW_SP_QDISC_RED,
670         .check_params = mlxsw_sp_qdisc_red_check_params,
671         .replace = mlxsw_sp_qdisc_red_replace,
672         .unoffload = mlxsw_sp_qdisc_red_unoffload,
673         .destroy = mlxsw_sp_qdisc_red_destroy,
674         .get_stats = mlxsw_sp_qdisc_get_red_stats,
675         .get_xstats = mlxsw_sp_qdisc_get_red_xstats,
676         .clean_stats = mlxsw_sp_setup_tc_qdisc_red_clean_stats,
677         .find_class = mlxsw_sp_qdisc_leaf_find_class,
678 };
679
680 static int __mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port,
681                                    struct tc_red_qopt_offload *p)
682 {
683         struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
684
685         mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, false);
686         if (!mlxsw_sp_qdisc)
687                 return -EOPNOTSUPP;
688
689         if (p->command == TC_RED_REPLACE)
690                 return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle,
691                                               mlxsw_sp_qdisc,
692                                               &mlxsw_sp_qdisc_ops_red,
693                                               &p->set);
694
695         if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle))
696                 return -EOPNOTSUPP;
697
698         switch (p->command) {
699         case TC_RED_DESTROY:
700                 return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
701         case TC_RED_XSTATS:
702                 return mlxsw_sp_qdisc_get_xstats(mlxsw_sp_port, mlxsw_sp_qdisc,
703                                                  p->xstats);
704         case TC_RED_STATS:
705                 return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
706                                                 &p->stats);
707         default:
708                 return -EOPNOTSUPP;
709         }
710 }
711
712 int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port,
713                           struct tc_red_qopt_offload *p)
714 {
715         int err;
716
717         mutex_lock(&mlxsw_sp_port->qdisc->lock);
718         err = __mlxsw_sp_setup_tc_red(mlxsw_sp_port, p);
719         mutex_unlock(&mlxsw_sp_port->qdisc->lock);
720
721         return err;
722 }
723
724 static void
725 mlxsw_sp_setup_tc_qdisc_leaf_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
726                                          struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
727 {
728         u64 backlog_cells = 0;
729         u64 tx_packets = 0;
730         u64 tx_bytes = 0;
731         u64 drops = 0;
732
733         mlxsw_sp_qdisc_collect_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
734                                         &tx_bytes, &tx_packets,
735                                         &drops, &backlog_cells);
736
737         mlxsw_sp_qdisc->stats_base.tx_packets = tx_packets;
738         mlxsw_sp_qdisc->stats_base.tx_bytes = tx_bytes;
739         mlxsw_sp_qdisc->stats_base.drops = drops;
740         mlxsw_sp_qdisc->stats_base.backlog = 0;
741 }
742
743 static int
744 mlxsw_sp_qdisc_tbf_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
745                            struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
746 {
747         return mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
748                                              MLXSW_REG_QEEC_HR_SUBGROUP,
749                                              mlxsw_sp_qdisc->tclass_num, 0,
750                                              MLXSW_REG_QEEC_MAS_DIS, 0);
751 }
752
753 static int
754 mlxsw_sp_qdisc_tbf_bs(struct mlxsw_sp_port *mlxsw_sp_port,
755                       u32 max_size, u8 *p_burst_size)
756 {
757         /* TBF burst size is configured in bytes. The ASIC burst size value is
758          * ((2 ^ bs) * 512 bits. Convert the TBF bytes to 512-bit units.
759          */
760         u32 bs512 = max_size / 64;
761         u8 bs = fls(bs512);
762
763         if (!bs)
764                 return -EINVAL;
765         --bs;
766
767         /* Demand a power of two. */
768         if ((1 << bs) != bs512)
769                 return -EINVAL;
770
771         if (bs < mlxsw_sp_port->mlxsw_sp->lowest_shaper_bs ||
772             bs > MLXSW_REG_QEEC_HIGHEST_SHAPER_BS)
773                 return -EINVAL;
774
775         *p_burst_size = bs;
776         return 0;
777 }
778
779 static u32
780 mlxsw_sp_qdisc_tbf_max_size(u8 bs)
781 {
782         return (1U << bs) * 64;
783 }
784
785 static u64
786 mlxsw_sp_qdisc_tbf_rate_kbps(struct tc_tbf_qopt_offload_replace_params *p)
787 {
788         /* TBF interface is in bytes/s, whereas Spectrum ASIC is configured in
789          * Kbits/s.
790          */
791         return div_u64(p->rate.rate_bytes_ps, 1000) * 8;
792 }
793
794 static int
795 mlxsw_sp_qdisc_tbf_check_params(struct mlxsw_sp_port *mlxsw_sp_port,
796                                 void *params)
797 {
798         struct tc_tbf_qopt_offload_replace_params *p = params;
799         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
800         u64 rate_kbps = mlxsw_sp_qdisc_tbf_rate_kbps(p);
801         u8 burst_size;
802         int err;
803
804         if (rate_kbps >= MLXSW_REG_QEEC_MAS_DIS) {
805                 dev_err(mlxsw_sp_port->mlxsw_sp->bus_info->dev,
806                         "spectrum: TBF: rate of %lluKbps must be below %u\n",
807                         rate_kbps, MLXSW_REG_QEEC_MAS_DIS);
808                 return -EINVAL;
809         }
810
811         err = mlxsw_sp_qdisc_tbf_bs(mlxsw_sp_port, p->max_size, &burst_size);
812         if (err) {
813                 u8 highest_shaper_bs = MLXSW_REG_QEEC_HIGHEST_SHAPER_BS;
814
815                 dev_err(mlxsw_sp->bus_info->dev,
816                         "spectrum: TBF: invalid burst size of %u, must be a power of two between %u and %u",
817                         p->max_size,
818                         mlxsw_sp_qdisc_tbf_max_size(mlxsw_sp->lowest_shaper_bs),
819                         mlxsw_sp_qdisc_tbf_max_size(highest_shaper_bs));
820                 return -EINVAL;
821         }
822
823         return 0;
824 }
825
826 static int
827 mlxsw_sp_qdisc_tbf_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
828                            struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
829                            void *params)
830 {
831         struct tc_tbf_qopt_offload_replace_params *p = params;
832         u64 rate_kbps = mlxsw_sp_qdisc_tbf_rate_kbps(p);
833         u8 burst_size;
834         int err;
835
836         err = mlxsw_sp_qdisc_tbf_bs(mlxsw_sp_port, p->max_size, &burst_size);
837         if (WARN_ON_ONCE(err))
838                 /* check_params above was supposed to reject this value. */
839                 return -EINVAL;
840
841         /* Configure subgroup shaper, so that both UC and MC traffic is subject
842          * to shaping. That is unlike RED, however UC queue lengths are going to
843          * be different than MC ones due to different pool and quota
844          * configurations, so the configuration is not applicable. For shaper on
845          * the other hand, subjecting the overall stream to the configured
846          * shaper makes sense. Also note that that is what we do for
847          * ieee_setmaxrate().
848          */
849         return mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
850                                              MLXSW_REG_QEEC_HR_SUBGROUP,
851                                              mlxsw_sp_qdisc->tclass_num, 0,
852                                              rate_kbps, burst_size);
853 }
854
855 static void
856 mlxsw_sp_qdisc_tbf_unoffload(struct mlxsw_sp_port *mlxsw_sp_port,
857                              struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
858                              void *params)
859 {
860         struct tc_tbf_qopt_offload_replace_params *p = params;
861
862         mlxsw_sp_qdisc_leaf_unoffload(mlxsw_sp_port, mlxsw_sp_qdisc, p->qstats);
863 }
864
865 static int
866 mlxsw_sp_qdisc_get_tbf_stats(struct mlxsw_sp_port *mlxsw_sp_port,
867                              struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
868                              struct tc_qopt_offload_stats *stats_ptr)
869 {
870         mlxsw_sp_qdisc_get_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
871                                     stats_ptr);
872         return 0;
873 }
874
875 static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_tbf = {
876         .type = MLXSW_SP_QDISC_TBF,
877         .check_params = mlxsw_sp_qdisc_tbf_check_params,
878         .replace = mlxsw_sp_qdisc_tbf_replace,
879         .unoffload = mlxsw_sp_qdisc_tbf_unoffload,
880         .destroy = mlxsw_sp_qdisc_tbf_destroy,
881         .get_stats = mlxsw_sp_qdisc_get_tbf_stats,
882         .clean_stats = mlxsw_sp_setup_tc_qdisc_leaf_clean_stats,
883         .find_class = mlxsw_sp_qdisc_leaf_find_class,
884 };
885
886 static int __mlxsw_sp_setup_tc_tbf(struct mlxsw_sp_port *mlxsw_sp_port,
887                                    struct tc_tbf_qopt_offload *p)
888 {
889         struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
890
891         mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, false);
892         if (!mlxsw_sp_qdisc)
893                 return -EOPNOTSUPP;
894
895         if (p->command == TC_TBF_REPLACE)
896                 return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle,
897                                               mlxsw_sp_qdisc,
898                                               &mlxsw_sp_qdisc_ops_tbf,
899                                               &p->replace_params);
900
901         if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle))
902                 return -EOPNOTSUPP;
903
904         switch (p->command) {
905         case TC_TBF_DESTROY:
906                 return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
907         case TC_TBF_STATS:
908                 return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
909                                                 &p->stats);
910         default:
911                 return -EOPNOTSUPP;
912         }
913 }
914
915 int mlxsw_sp_setup_tc_tbf(struct mlxsw_sp_port *mlxsw_sp_port,
916                           struct tc_tbf_qopt_offload *p)
917 {
918         int err;
919
920         mutex_lock(&mlxsw_sp_port->qdisc->lock);
921         err = __mlxsw_sp_setup_tc_tbf(mlxsw_sp_port, p);
922         mutex_unlock(&mlxsw_sp_port->qdisc->lock);
923
924         return err;
925 }
926
927 static int
928 mlxsw_sp_qdisc_fifo_check_params(struct mlxsw_sp_port *mlxsw_sp_port,
929                                  void *params)
930 {
931         return 0;
932 }
933
934 static int
935 mlxsw_sp_qdisc_fifo_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
936                             struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
937                             void *params)
938 {
939         return 0;
940 }
941
942 static int
943 mlxsw_sp_qdisc_get_fifo_stats(struct mlxsw_sp_port *mlxsw_sp_port,
944                               struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
945                               struct tc_qopt_offload_stats *stats_ptr)
946 {
947         mlxsw_sp_qdisc_get_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
948                                     stats_ptr);
949         return 0;
950 }
951
952 static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_fifo = {
953         .type = MLXSW_SP_QDISC_FIFO,
954         .check_params = mlxsw_sp_qdisc_fifo_check_params,
955         .replace = mlxsw_sp_qdisc_fifo_replace,
956         .get_stats = mlxsw_sp_qdisc_get_fifo_stats,
957         .clean_stats = mlxsw_sp_setup_tc_qdisc_leaf_clean_stats,
958 };
959
960 static int __mlxsw_sp_setup_tc_fifo(struct mlxsw_sp_port *mlxsw_sp_port,
961                                     struct tc_fifo_qopt_offload *p)
962 {
963         struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc;
964         struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
965         unsigned int band;
966         u32 parent_handle;
967
968         mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, false);
969         if (!mlxsw_sp_qdisc && p->handle == TC_H_UNSPEC) {
970                 parent_handle = TC_H_MAJ(p->parent);
971                 if (parent_handle != qdisc_state->future_handle) {
972                         /* This notifications is for a different Qdisc than
973                          * previously. Wipe the future cache.
974                          */
975                         memset(qdisc_state->future_fifos, 0,
976                                sizeof(qdisc_state->future_fifos));
977                         qdisc_state->future_handle = parent_handle;
978                 }
979
980                 band = TC_H_MIN(p->parent) - 1;
981                 if (band < IEEE_8021QAZ_MAX_TCS) {
982                         if (p->command == TC_FIFO_REPLACE)
983                                 qdisc_state->future_fifos[band] = true;
984                         else if (p->command == TC_FIFO_DESTROY)
985                                 qdisc_state->future_fifos[band] = false;
986                 }
987         }
988         if (!mlxsw_sp_qdisc)
989                 return -EOPNOTSUPP;
990
991         if (p->command == TC_FIFO_REPLACE) {
992                 return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle,
993                                               mlxsw_sp_qdisc,
994                                               &mlxsw_sp_qdisc_ops_fifo, NULL);
995         }
996
997         if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle))
998                 return -EOPNOTSUPP;
999
1000         switch (p->command) {
1001         case TC_FIFO_DESTROY:
1002                 return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
1003         case TC_FIFO_STATS:
1004                 return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
1005                                                 &p->stats);
1006         case TC_FIFO_REPLACE: /* Handled above. */
1007                 break;
1008         }
1009
1010         return -EOPNOTSUPP;
1011 }
1012
1013 int mlxsw_sp_setup_tc_fifo(struct mlxsw_sp_port *mlxsw_sp_port,
1014                            struct tc_fifo_qopt_offload *p)
1015 {
1016         int err;
1017
1018         mutex_lock(&mlxsw_sp_port->qdisc->lock);
1019         err = __mlxsw_sp_setup_tc_fifo(mlxsw_sp_port, p);
1020         mutex_unlock(&mlxsw_sp_port->qdisc->lock);
1021
1022         return err;
1023 }
1024
1025 static int __mlxsw_sp_qdisc_ets_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
1026                                         struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
1027 {
1028         int i;
1029
1030         for (i = 0; i < mlxsw_sp_qdisc->num_classes; i++) {
1031                 mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i,
1032                                           MLXSW_SP_PORT_DEFAULT_TCLASS);
1033                 mlxsw_sp_port_ets_set(mlxsw_sp_port,
1034                                       MLXSW_REG_QEEC_HR_SUBGROUP,
1035                                       i, 0, false, 0);
1036                 mlxsw_sp_qdisc_destroy(mlxsw_sp_port,
1037                                        &mlxsw_sp_qdisc->qdiscs[i]);
1038                 mlxsw_sp_qdisc->qdiscs[i].prio_bitmap = 0;
1039         }
1040
1041         return 0;
1042 }
1043
1044 static int
1045 mlxsw_sp_qdisc_prio_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
1046                             struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
1047 {
1048         return __mlxsw_sp_qdisc_ets_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
1049 }
1050
1051 static int
1052 __mlxsw_sp_qdisc_ets_check_params(unsigned int nbands)
1053 {
1054         if (nbands > IEEE_8021QAZ_MAX_TCS)
1055                 return -EOPNOTSUPP;
1056
1057         return 0;
1058 }
1059
1060 static int
1061 mlxsw_sp_qdisc_prio_check_params(struct mlxsw_sp_port *mlxsw_sp_port,
1062                                  void *params)
1063 {
1064         struct tc_prio_qopt_offload_params *p = params;
1065
1066         return __mlxsw_sp_qdisc_ets_check_params(p->bands);
1067 }
1068
1069 static int
1070 __mlxsw_sp_qdisc_ets_replace(struct mlxsw_sp_port *mlxsw_sp_port,
1071                              struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
1072                              u32 handle, unsigned int nbands,
1073                              const unsigned int *quanta,
1074                              const unsigned int *weights,
1075                              const u8 *priomap)
1076 {
1077         struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc;
1078         struct mlxsw_sp_qdisc *child_qdisc;
1079         int tclass, i, band, backlog;
1080         u8 old_priomap;
1081         int err;
1082
1083         for (band = 0; band < nbands; band++) {
1084                 tclass = MLXSW_SP_PRIO_BAND_TO_TCLASS(band);
1085                 child_qdisc = &mlxsw_sp_qdisc->qdiscs[band];
1086                 old_priomap = child_qdisc->prio_bitmap;
1087                 child_qdisc->prio_bitmap = 0;
1088
1089                 err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
1090                                             MLXSW_REG_QEEC_HR_SUBGROUP,
1091                                             tclass, 0, !!quanta[band],
1092                                             weights[band]);
1093                 if (err)
1094                         return err;
1095
1096                 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
1097                         if (priomap[i] == band) {
1098                                 child_qdisc->prio_bitmap |= BIT(i);
1099                                 if (BIT(i) & old_priomap)
1100                                         continue;
1101                                 err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port,
1102                                                                 i, tclass);
1103                                 if (err)
1104                                         return err;
1105                         }
1106                 }
1107
1108                 child_qdisc->tclass_num = tclass;
1109
1110                 if (old_priomap != child_qdisc->prio_bitmap &&
1111                     child_qdisc->ops && child_qdisc->ops->clean_stats) {
1112                         backlog = child_qdisc->stats_base.backlog;
1113                         child_qdisc->ops->clean_stats(mlxsw_sp_port,
1114                                                       child_qdisc);
1115                         child_qdisc->stats_base.backlog = backlog;
1116                 }
1117
1118                 if (handle == qdisc_state->future_handle &&
1119                     qdisc_state->future_fifos[band]) {
1120                         err = mlxsw_sp_qdisc_replace(mlxsw_sp_port, TC_H_UNSPEC,
1121                                                      child_qdisc,
1122                                                      &mlxsw_sp_qdisc_ops_fifo,
1123                                                      NULL);
1124                         if (err)
1125                                 return err;
1126                 }
1127         }
1128         for (; band < IEEE_8021QAZ_MAX_TCS; band++) {
1129                 tclass = MLXSW_SP_PRIO_BAND_TO_TCLASS(band);
1130                 child_qdisc = &mlxsw_sp_qdisc->qdiscs[band];
1131                 child_qdisc->prio_bitmap = 0;
1132                 mlxsw_sp_qdisc_destroy(mlxsw_sp_port, child_qdisc);
1133                 mlxsw_sp_port_ets_set(mlxsw_sp_port,
1134                                       MLXSW_REG_QEEC_HR_SUBGROUP,
1135                                       tclass, 0, false, 0);
1136         }
1137
1138         qdisc_state->future_handle = TC_H_UNSPEC;
1139         memset(qdisc_state->future_fifos, 0, sizeof(qdisc_state->future_fifos));
1140         return 0;
1141 }
1142
1143 static int
1144 mlxsw_sp_qdisc_prio_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
1145                             struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
1146                             void *params)
1147 {
1148         struct tc_prio_qopt_offload_params *p = params;
1149         unsigned int zeroes[TCQ_ETS_MAX_BANDS] = {0};
1150
1151         return __mlxsw_sp_qdisc_ets_replace(mlxsw_sp_port, mlxsw_sp_qdisc,
1152                                             handle, p->bands, zeroes,
1153                                             zeroes, p->priomap);
1154 }
1155
1156 static void
1157 __mlxsw_sp_qdisc_ets_unoffload(struct mlxsw_sp_port *mlxsw_sp_port,
1158                                struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
1159                                struct gnet_stats_queue *qstats)
1160 {
1161         u64 backlog;
1162
1163         backlog = mlxsw_sp_cells_bytes(mlxsw_sp_port->mlxsw_sp,
1164                                        mlxsw_sp_qdisc->stats_base.backlog);
1165         qstats->backlog -= backlog;
1166 }
1167
1168 static void
1169 mlxsw_sp_qdisc_prio_unoffload(struct mlxsw_sp_port *mlxsw_sp_port,
1170                               struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
1171                               void *params)
1172 {
1173         struct tc_prio_qopt_offload_params *p = params;
1174
1175         __mlxsw_sp_qdisc_ets_unoffload(mlxsw_sp_port, mlxsw_sp_qdisc,
1176                                        p->qstats);
1177 }
1178
1179 static int
1180 mlxsw_sp_qdisc_get_prio_stats(struct mlxsw_sp_port *mlxsw_sp_port,
1181                               struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
1182                               struct tc_qopt_offload_stats *stats_ptr)
1183 {
1184         struct mlxsw_sp_qdisc *tc_qdisc;
1185         u64 tx_packets = 0;
1186         u64 tx_bytes = 0;
1187         u64 backlog = 0;
1188         u64 drops = 0;
1189         int i;
1190
1191         for (i = 0; i < mlxsw_sp_qdisc->num_classes; i++) {
1192                 tc_qdisc = &mlxsw_sp_qdisc->qdiscs[i];
1193                 mlxsw_sp_qdisc_collect_tc_stats(mlxsw_sp_port, tc_qdisc,
1194                                                 &tx_bytes, &tx_packets,
1195                                                 &drops, &backlog);
1196         }
1197
1198         mlxsw_sp_qdisc_update_stats(mlxsw_sp_port->mlxsw_sp, mlxsw_sp_qdisc,
1199                                     tx_bytes, tx_packets, drops, backlog,
1200                                     stats_ptr);
1201         return 0;
1202 }
1203
1204 static void
1205 mlxsw_sp_setup_tc_qdisc_prio_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
1206                                          struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
1207 {
1208         struct mlxsw_sp_qdisc_stats *stats_base;
1209         struct mlxsw_sp_port_xstats *xstats;
1210         struct rtnl_link_stats64 *stats;
1211         int i;
1212
1213         xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
1214         stats = &mlxsw_sp_port->periodic_hw_stats.stats;
1215         stats_base = &mlxsw_sp_qdisc->stats_base;
1216
1217         stats_base->tx_packets = stats->tx_packets;
1218         stats_base->tx_bytes = stats->tx_bytes;
1219
1220         stats_base->drops = 0;
1221         for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
1222                 stats_base->drops += mlxsw_sp_xstats_tail_drop(xstats, i);
1223                 stats_base->drops += xstats->wred_drop[i];
1224         }
1225
1226         mlxsw_sp_qdisc->stats_base.backlog = 0;
1227 }
1228
1229 static struct mlxsw_sp_qdisc *
1230 mlxsw_sp_qdisc_prio_find_class(struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
1231                                u32 parent)
1232 {
1233         int child_index = TC_H_MIN(parent);
1234         int band = child_index - 1;
1235
1236         if (band < 0 || band >= mlxsw_sp_qdisc->num_classes)
1237                 return NULL;
1238         return &mlxsw_sp_qdisc->qdiscs[band];
1239 }
1240
1241 static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_prio = {
1242         .type = MLXSW_SP_QDISC_PRIO,
1243         .check_params = mlxsw_sp_qdisc_prio_check_params,
1244         .replace = mlxsw_sp_qdisc_prio_replace,
1245         .unoffload = mlxsw_sp_qdisc_prio_unoffload,
1246         .destroy = mlxsw_sp_qdisc_prio_destroy,
1247         .get_stats = mlxsw_sp_qdisc_get_prio_stats,
1248         .clean_stats = mlxsw_sp_setup_tc_qdisc_prio_clean_stats,
1249         .find_class = mlxsw_sp_qdisc_prio_find_class,
1250         .num_classes = IEEE_8021QAZ_MAX_TCS,
1251 };
1252
1253 static int
1254 mlxsw_sp_qdisc_ets_check_params(struct mlxsw_sp_port *mlxsw_sp_port,
1255                                 void *params)
1256 {
1257         struct tc_ets_qopt_offload_replace_params *p = params;
1258
1259         return __mlxsw_sp_qdisc_ets_check_params(p->bands);
1260 }
1261
1262 static int
1263 mlxsw_sp_qdisc_ets_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
1264                            struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
1265                            void *params)
1266 {
1267         struct tc_ets_qopt_offload_replace_params *p = params;
1268
1269         return __mlxsw_sp_qdisc_ets_replace(mlxsw_sp_port, mlxsw_sp_qdisc,
1270                                             handle, p->bands, p->quanta,
1271                                             p->weights, p->priomap);
1272 }
1273
1274 static void
1275 mlxsw_sp_qdisc_ets_unoffload(struct mlxsw_sp_port *mlxsw_sp_port,
1276                              struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
1277                              void *params)
1278 {
1279         struct tc_ets_qopt_offload_replace_params *p = params;
1280
1281         __mlxsw_sp_qdisc_ets_unoffload(mlxsw_sp_port, mlxsw_sp_qdisc,
1282                                        p->qstats);
1283 }
1284
1285 static int
1286 mlxsw_sp_qdisc_ets_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
1287                            struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
1288 {
1289         return __mlxsw_sp_qdisc_ets_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
1290 }
1291
1292 static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_ets = {
1293         .type = MLXSW_SP_QDISC_ETS,
1294         .check_params = mlxsw_sp_qdisc_ets_check_params,
1295         .replace = mlxsw_sp_qdisc_ets_replace,
1296         .unoffload = mlxsw_sp_qdisc_ets_unoffload,
1297         .destroy = mlxsw_sp_qdisc_ets_destroy,
1298         .get_stats = mlxsw_sp_qdisc_get_prio_stats,
1299         .clean_stats = mlxsw_sp_setup_tc_qdisc_prio_clean_stats,
1300         .find_class = mlxsw_sp_qdisc_prio_find_class,
1301         .num_classes = IEEE_8021QAZ_MAX_TCS,
1302 };
1303
1304 /* Linux allows linking of Qdiscs to arbitrary classes (so long as the resulting
1305  * graph is free of cycles). These operations do not change the parent handle
1306  * though, which means it can be incomplete (if there is more than one class
1307  * where the Qdisc in question is grafted) or outright wrong (if the Qdisc was
1308  * linked to a different class and then removed from the original class).
1309  *
1310  * E.g. consider this sequence of operations:
1311  *
1312  *  # tc qdisc add dev swp1 root handle 1: prio
1313  *  # tc qdisc add dev swp1 parent 1:3 handle 13: red limit 1000000 avpkt 10000
1314  *  RED: set bandwidth to 10Mbit
1315  *  # tc qdisc link dev swp1 handle 13: parent 1:2
1316  *
1317  * At this point, both 1:2 and 1:3 have the same RED Qdisc instance as their
1318  * child. But RED will still only claim that 1:3 is its parent. If it's removed
1319  * from that band, its only parent will be 1:2, but it will continue to claim
1320  * that it is in fact 1:3.
1321  *
1322  * The notification for child Qdisc replace (e.g. TC_RED_REPLACE) comes before
1323  * the notification for parent graft (e.g. TC_PRIO_GRAFT). We take the replace
1324  * notification to offload the child Qdisc, based on its parent handle, and use
1325  * the graft operation to validate that the class where the child is actually
1326  * grafted corresponds to the parent handle. If the two don't match, we
1327  * unoffload the child.
1328  */
1329 static int
1330 __mlxsw_sp_qdisc_ets_graft(struct mlxsw_sp_port *mlxsw_sp_port,
1331                            struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
1332                            u8 band, u32 child_handle)
1333 {
1334         struct mlxsw_sp_qdisc *old_qdisc;
1335         u32 parent;
1336
1337         if (band < mlxsw_sp_qdisc->num_classes &&
1338             mlxsw_sp_qdisc->qdiscs[band].handle == child_handle)
1339                 return 0;
1340
1341         if (!child_handle) {
1342                 /* This is an invisible FIFO replacing the original Qdisc.
1343                  * Ignore it--the original Qdisc's destroy will follow.
1344                  */
1345                 return 0;
1346         }
1347
1348         /* See if the grafted qdisc is already offloaded on any tclass. If so,
1349          * unoffload it.
1350          */
1351         old_qdisc = mlxsw_sp_qdisc_find_by_handle(mlxsw_sp_port,
1352                                                   child_handle);
1353         if (old_qdisc)
1354                 mlxsw_sp_qdisc_destroy(mlxsw_sp_port, old_qdisc);
1355
1356         parent = TC_H_MAKE(mlxsw_sp_qdisc->handle, band + 1);
1357         mlxsw_sp_qdisc = mlxsw_sp_qdisc->ops->find_class(mlxsw_sp_qdisc,
1358                                                          parent);
1359         if (!WARN_ON(!mlxsw_sp_qdisc))
1360                 mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
1361
1362         return -EOPNOTSUPP;
1363 }
1364
1365 static int
1366 mlxsw_sp_qdisc_prio_graft(struct mlxsw_sp_port *mlxsw_sp_port,
1367                           struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
1368                           struct tc_prio_qopt_offload_graft_params *p)
1369 {
1370         return __mlxsw_sp_qdisc_ets_graft(mlxsw_sp_port, mlxsw_sp_qdisc,
1371                                           p->band, p->child_handle);
1372 }
1373
1374 static int __mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
1375                                     struct tc_prio_qopt_offload *p)
1376 {
1377         struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
1378
1379         mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, true);
1380         if (!mlxsw_sp_qdisc)
1381                 return -EOPNOTSUPP;
1382
1383         if (p->command == TC_PRIO_REPLACE)
1384                 return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle,
1385                                               mlxsw_sp_qdisc,
1386                                               &mlxsw_sp_qdisc_ops_prio,
1387                                               &p->replace_params);
1388
1389         if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle))
1390                 return -EOPNOTSUPP;
1391
1392         switch (p->command) {
1393         case TC_PRIO_DESTROY:
1394                 return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
1395         case TC_PRIO_STATS:
1396                 return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
1397                                                 &p->stats);
1398         case TC_PRIO_GRAFT:
1399                 return mlxsw_sp_qdisc_prio_graft(mlxsw_sp_port, mlxsw_sp_qdisc,
1400                                                  &p->graft_params);
1401         default:
1402                 return -EOPNOTSUPP;
1403         }
1404 }
1405
1406 int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
1407                            struct tc_prio_qopt_offload *p)
1408 {
1409         int err;
1410
1411         mutex_lock(&mlxsw_sp_port->qdisc->lock);
1412         err = __mlxsw_sp_setup_tc_prio(mlxsw_sp_port, p);
1413         mutex_unlock(&mlxsw_sp_port->qdisc->lock);
1414
1415         return err;
1416 }
1417
1418 static int __mlxsw_sp_setup_tc_ets(struct mlxsw_sp_port *mlxsw_sp_port,
1419                                    struct tc_ets_qopt_offload *p)
1420 {
1421         struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
1422
1423         mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, true);
1424         if (!mlxsw_sp_qdisc)
1425                 return -EOPNOTSUPP;
1426
1427         if (p->command == TC_ETS_REPLACE)
1428                 return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle,
1429                                               mlxsw_sp_qdisc,
1430                                               &mlxsw_sp_qdisc_ops_ets,
1431                                               &p->replace_params);
1432
1433         if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle))
1434                 return -EOPNOTSUPP;
1435
1436         switch (p->command) {
1437         case TC_ETS_DESTROY:
1438                 return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
1439         case TC_ETS_STATS:
1440                 return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
1441                                                 &p->stats);
1442         case TC_ETS_GRAFT:
1443                 return __mlxsw_sp_qdisc_ets_graft(mlxsw_sp_port, mlxsw_sp_qdisc,
1444                                                   p->graft_params.band,
1445                                                   p->graft_params.child_handle);
1446         default:
1447                 return -EOPNOTSUPP;
1448         }
1449 }
1450
1451 int mlxsw_sp_setup_tc_ets(struct mlxsw_sp_port *mlxsw_sp_port,
1452                           struct tc_ets_qopt_offload *p)
1453 {
1454         int err;
1455
1456         mutex_lock(&mlxsw_sp_port->qdisc->lock);
1457         err = __mlxsw_sp_setup_tc_ets(mlxsw_sp_port, p);
1458         mutex_unlock(&mlxsw_sp_port->qdisc->lock);
1459
1460         return err;
1461 }
1462
1463 struct mlxsw_sp_qevent_block {
1464         struct list_head binding_list;
1465         struct list_head mall_entry_list;
1466         struct mlxsw_sp *mlxsw_sp;
1467 };
1468
1469 struct mlxsw_sp_qevent_binding {
1470         struct list_head list;
1471         struct mlxsw_sp_port *mlxsw_sp_port;
1472         u32 handle;
1473         int tclass_num;
1474         enum mlxsw_sp_span_trigger span_trigger;
1475 };
1476
1477 static LIST_HEAD(mlxsw_sp_qevent_block_cb_list);
1478
1479 static int mlxsw_sp_qevent_span_configure(struct mlxsw_sp *mlxsw_sp,
1480                                           struct mlxsw_sp_mall_entry *mall_entry,
1481                                           struct mlxsw_sp_qevent_binding *qevent_binding,
1482                                           const struct mlxsw_sp_span_agent_parms *agent_parms,
1483                                           int *p_span_id)
1484 {
1485         struct mlxsw_sp_port *mlxsw_sp_port = qevent_binding->mlxsw_sp_port;
1486         struct mlxsw_sp_span_trigger_parms trigger_parms = {};
1487         int span_id;
1488         int err;
1489
1490         err = mlxsw_sp_span_agent_get(mlxsw_sp, &span_id, agent_parms);
1491         if (err)
1492                 return err;
1493
1494         err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, true);
1495         if (err)
1496                 goto err_analyzed_port_get;
1497
1498         trigger_parms.span_id = span_id;
1499         trigger_parms.probability_rate = 1;
1500         err = mlxsw_sp_span_agent_bind(mlxsw_sp, qevent_binding->span_trigger, mlxsw_sp_port,
1501                                        &trigger_parms);
1502         if (err)
1503                 goto err_agent_bind;
1504
1505         err = mlxsw_sp_span_trigger_enable(mlxsw_sp_port, qevent_binding->span_trigger,
1506                                            qevent_binding->tclass_num);
1507         if (err)
1508                 goto err_trigger_enable;
1509
1510         *p_span_id = span_id;
1511         return 0;
1512
1513 err_trigger_enable:
1514         mlxsw_sp_span_agent_unbind(mlxsw_sp, qevent_binding->span_trigger, mlxsw_sp_port,
1515                                    &trigger_parms);
1516 err_agent_bind:
1517         mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true);
1518 err_analyzed_port_get:
1519         mlxsw_sp_span_agent_put(mlxsw_sp, span_id);
1520         return err;
1521 }
1522
1523 static void mlxsw_sp_qevent_span_deconfigure(struct mlxsw_sp *mlxsw_sp,
1524                                              struct mlxsw_sp_qevent_binding *qevent_binding,
1525                                              int span_id)
1526 {
1527         struct mlxsw_sp_port *mlxsw_sp_port = qevent_binding->mlxsw_sp_port;
1528         struct mlxsw_sp_span_trigger_parms trigger_parms = {
1529                 .span_id = span_id,
1530         };
1531
1532         mlxsw_sp_span_trigger_disable(mlxsw_sp_port, qevent_binding->span_trigger,
1533                                       qevent_binding->tclass_num);
1534         mlxsw_sp_span_agent_unbind(mlxsw_sp, qevent_binding->span_trigger, mlxsw_sp_port,
1535                                    &trigger_parms);
1536         mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true);
1537         mlxsw_sp_span_agent_put(mlxsw_sp, span_id);
1538 }
1539
1540 static int mlxsw_sp_qevent_mirror_configure(struct mlxsw_sp *mlxsw_sp,
1541                                             struct mlxsw_sp_mall_entry *mall_entry,
1542                                             struct mlxsw_sp_qevent_binding *qevent_binding)
1543 {
1544         struct mlxsw_sp_span_agent_parms agent_parms = {
1545                 .to_dev = mall_entry->mirror.to_dev,
1546         };
1547
1548         return mlxsw_sp_qevent_span_configure(mlxsw_sp, mall_entry, qevent_binding,
1549                                               &agent_parms, &mall_entry->mirror.span_id);
1550 }
1551
1552 static void mlxsw_sp_qevent_mirror_deconfigure(struct mlxsw_sp *mlxsw_sp,
1553                                                struct mlxsw_sp_mall_entry *mall_entry,
1554                                                struct mlxsw_sp_qevent_binding *qevent_binding)
1555 {
1556         mlxsw_sp_qevent_span_deconfigure(mlxsw_sp, qevent_binding, mall_entry->mirror.span_id);
1557 }
1558
1559 static int mlxsw_sp_qevent_trap_configure(struct mlxsw_sp *mlxsw_sp,
1560                                           struct mlxsw_sp_mall_entry *mall_entry,
1561                                           struct mlxsw_sp_qevent_binding *qevent_binding)
1562 {
1563         struct mlxsw_sp_span_agent_parms agent_parms = {
1564                 .session_id = MLXSW_SP_SPAN_SESSION_ID_BUFFER,
1565         };
1566         int err;
1567
1568         err = mlxsw_sp_trap_group_policer_hw_id_get(mlxsw_sp,
1569                                                     DEVLINK_TRAP_GROUP_GENERIC_ID_BUFFER_DROPS,
1570                                                     &agent_parms.policer_enable,
1571                                                     &agent_parms.policer_id);
1572         if (err)
1573                 return err;
1574
1575         return mlxsw_sp_qevent_span_configure(mlxsw_sp, mall_entry, qevent_binding,
1576                                               &agent_parms, &mall_entry->trap.span_id);
1577 }
1578
1579 static void mlxsw_sp_qevent_trap_deconfigure(struct mlxsw_sp *mlxsw_sp,
1580                                              struct mlxsw_sp_mall_entry *mall_entry,
1581                                              struct mlxsw_sp_qevent_binding *qevent_binding)
1582 {
1583         mlxsw_sp_qevent_span_deconfigure(mlxsw_sp, qevent_binding, mall_entry->trap.span_id);
1584 }
1585
1586 static int mlxsw_sp_qevent_entry_configure(struct mlxsw_sp *mlxsw_sp,
1587                                            struct mlxsw_sp_mall_entry *mall_entry,
1588                                            struct mlxsw_sp_qevent_binding *qevent_binding)
1589 {
1590         switch (mall_entry->type) {
1591         case MLXSW_SP_MALL_ACTION_TYPE_MIRROR:
1592                 return mlxsw_sp_qevent_mirror_configure(mlxsw_sp, mall_entry, qevent_binding);
1593         case MLXSW_SP_MALL_ACTION_TYPE_TRAP:
1594                 return mlxsw_sp_qevent_trap_configure(mlxsw_sp, mall_entry, qevent_binding);
1595         default:
1596                 /* This should have been validated away. */
1597                 WARN_ON(1);
1598                 return -EOPNOTSUPP;
1599         }
1600 }
1601
1602 static void mlxsw_sp_qevent_entry_deconfigure(struct mlxsw_sp *mlxsw_sp,
1603                                               struct mlxsw_sp_mall_entry *mall_entry,
1604                                               struct mlxsw_sp_qevent_binding *qevent_binding)
1605 {
1606         switch (mall_entry->type) {
1607         case MLXSW_SP_MALL_ACTION_TYPE_MIRROR:
1608                 return mlxsw_sp_qevent_mirror_deconfigure(mlxsw_sp, mall_entry, qevent_binding);
1609         case MLXSW_SP_MALL_ACTION_TYPE_TRAP:
1610                 return mlxsw_sp_qevent_trap_deconfigure(mlxsw_sp, mall_entry, qevent_binding);
1611         default:
1612                 WARN_ON(1);
1613                 return;
1614         }
1615 }
1616
1617 static int mlxsw_sp_qevent_binding_configure(struct mlxsw_sp_qevent_block *qevent_block,
1618                                              struct mlxsw_sp_qevent_binding *qevent_binding)
1619 {
1620         struct mlxsw_sp_mall_entry *mall_entry;
1621         int err;
1622
1623         list_for_each_entry(mall_entry, &qevent_block->mall_entry_list, list) {
1624                 err = mlxsw_sp_qevent_entry_configure(qevent_block->mlxsw_sp, mall_entry,
1625                                                       qevent_binding);
1626                 if (err)
1627                         goto err_entry_configure;
1628         }
1629
1630         return 0;
1631
1632 err_entry_configure:
1633         list_for_each_entry_continue_reverse(mall_entry, &qevent_block->mall_entry_list, list)
1634                 mlxsw_sp_qevent_entry_deconfigure(qevent_block->mlxsw_sp, mall_entry,
1635                                                   qevent_binding);
1636         return err;
1637 }
1638
1639 static void mlxsw_sp_qevent_binding_deconfigure(struct mlxsw_sp_qevent_block *qevent_block,
1640                                                 struct mlxsw_sp_qevent_binding *qevent_binding)
1641 {
1642         struct mlxsw_sp_mall_entry *mall_entry;
1643
1644         list_for_each_entry(mall_entry, &qevent_block->mall_entry_list, list)
1645                 mlxsw_sp_qevent_entry_deconfigure(qevent_block->mlxsw_sp, mall_entry,
1646                                                   qevent_binding);
1647 }
1648
1649 static int mlxsw_sp_qevent_block_configure(struct mlxsw_sp_qevent_block *qevent_block)
1650 {
1651         struct mlxsw_sp_qevent_binding *qevent_binding;
1652         int err;
1653
1654         list_for_each_entry(qevent_binding, &qevent_block->binding_list, list) {
1655                 err = mlxsw_sp_qevent_binding_configure(qevent_block, qevent_binding);
1656                 if (err)
1657                         goto err_binding_configure;
1658         }
1659
1660         return 0;
1661
1662 err_binding_configure:
1663         list_for_each_entry_continue_reverse(qevent_binding, &qevent_block->binding_list, list)
1664                 mlxsw_sp_qevent_binding_deconfigure(qevent_block, qevent_binding);
1665         return err;
1666 }
1667
1668 static void mlxsw_sp_qevent_block_deconfigure(struct mlxsw_sp_qevent_block *qevent_block)
1669 {
1670         struct mlxsw_sp_qevent_binding *qevent_binding;
1671
1672         list_for_each_entry(qevent_binding, &qevent_block->binding_list, list)
1673                 mlxsw_sp_qevent_binding_deconfigure(qevent_block, qevent_binding);
1674 }
1675
1676 static struct mlxsw_sp_mall_entry *
1677 mlxsw_sp_qevent_mall_entry_find(struct mlxsw_sp_qevent_block *block, unsigned long cookie)
1678 {
1679         struct mlxsw_sp_mall_entry *mall_entry;
1680
1681         list_for_each_entry(mall_entry, &block->mall_entry_list, list)
1682                 if (mall_entry->cookie == cookie)
1683                         return mall_entry;
1684
1685         return NULL;
1686 }
1687
1688 static int mlxsw_sp_qevent_mall_replace(struct mlxsw_sp *mlxsw_sp,
1689                                         struct mlxsw_sp_qevent_block *qevent_block,
1690                                         struct tc_cls_matchall_offload *f)
1691 {
1692         struct mlxsw_sp_mall_entry *mall_entry;
1693         struct flow_action_entry *act;
1694         int err;
1695
1696         /* It should not currently be possible to replace a matchall rule. So
1697          * this must be a new rule.
1698          */
1699         if (!list_empty(&qevent_block->mall_entry_list)) {
1700                 NL_SET_ERR_MSG(f->common.extack, "At most one filter supported");
1701                 return -EOPNOTSUPP;
1702         }
1703         if (f->rule->action.num_entries != 1) {
1704                 NL_SET_ERR_MSG(f->common.extack, "Only singular actions supported");
1705                 return -EOPNOTSUPP;
1706         }
1707         if (f->common.chain_index) {
1708                 NL_SET_ERR_MSG(f->common.extack, "Only chain 0 is supported");
1709                 return -EOPNOTSUPP;
1710         }
1711         if (f->common.protocol != htons(ETH_P_ALL)) {
1712                 NL_SET_ERR_MSG(f->common.extack, "Protocol matching not supported");
1713                 return -EOPNOTSUPP;
1714         }
1715
1716         act = &f->rule->action.entries[0];
1717         if (!(act->hw_stats & FLOW_ACTION_HW_STATS_DISABLED)) {
1718                 NL_SET_ERR_MSG(f->common.extack, "HW counters not supported on qevents");
1719                 return -EOPNOTSUPP;
1720         }
1721
1722         mall_entry = kzalloc(sizeof(*mall_entry), GFP_KERNEL);
1723         if (!mall_entry)
1724                 return -ENOMEM;
1725         mall_entry->cookie = f->cookie;
1726
1727         if (act->id == FLOW_ACTION_MIRRED) {
1728                 mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_MIRROR;
1729                 mall_entry->mirror.to_dev = act->dev;
1730         } else if (act->id == FLOW_ACTION_TRAP) {
1731                 mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_TRAP;
1732         } else {
1733                 NL_SET_ERR_MSG(f->common.extack, "Unsupported action");
1734                 err = -EOPNOTSUPP;
1735                 goto err_unsupported_action;
1736         }
1737
1738         list_add_tail(&mall_entry->list, &qevent_block->mall_entry_list);
1739
1740         err = mlxsw_sp_qevent_block_configure(qevent_block);
1741         if (err)
1742                 goto err_block_configure;
1743
1744         return 0;
1745
1746 err_block_configure:
1747         list_del(&mall_entry->list);
1748 err_unsupported_action:
1749         kfree(mall_entry);
1750         return err;
1751 }
1752
1753 static void mlxsw_sp_qevent_mall_destroy(struct mlxsw_sp_qevent_block *qevent_block,
1754                                          struct tc_cls_matchall_offload *f)
1755 {
1756         struct mlxsw_sp_mall_entry *mall_entry;
1757
1758         mall_entry = mlxsw_sp_qevent_mall_entry_find(qevent_block, f->cookie);
1759         if (!mall_entry)
1760                 return;
1761
1762         mlxsw_sp_qevent_block_deconfigure(qevent_block);
1763
1764         list_del(&mall_entry->list);
1765         kfree(mall_entry);
1766 }
1767
1768 static int mlxsw_sp_qevent_block_mall_cb(struct mlxsw_sp_qevent_block *qevent_block,
1769                                          struct tc_cls_matchall_offload *f)
1770 {
1771         struct mlxsw_sp *mlxsw_sp = qevent_block->mlxsw_sp;
1772
1773         switch (f->command) {
1774         case TC_CLSMATCHALL_REPLACE:
1775                 return mlxsw_sp_qevent_mall_replace(mlxsw_sp, qevent_block, f);
1776         case TC_CLSMATCHALL_DESTROY:
1777                 mlxsw_sp_qevent_mall_destroy(qevent_block, f);
1778                 return 0;
1779         default:
1780                 return -EOPNOTSUPP;
1781         }
1782 }
1783
1784 static int mlxsw_sp_qevent_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
1785 {
1786         struct mlxsw_sp_qevent_block *qevent_block = cb_priv;
1787
1788         switch (type) {
1789         case TC_SETUP_CLSMATCHALL:
1790                 return mlxsw_sp_qevent_block_mall_cb(qevent_block, type_data);
1791         default:
1792                 return -EOPNOTSUPP;
1793         }
1794 }
1795
1796 static struct mlxsw_sp_qevent_block *mlxsw_sp_qevent_block_create(struct mlxsw_sp *mlxsw_sp,
1797                                                                   struct net *net)
1798 {
1799         struct mlxsw_sp_qevent_block *qevent_block;
1800
1801         qevent_block = kzalloc(sizeof(*qevent_block), GFP_KERNEL);
1802         if (!qevent_block)
1803                 return NULL;
1804
1805         INIT_LIST_HEAD(&qevent_block->binding_list);
1806         INIT_LIST_HEAD(&qevent_block->mall_entry_list);
1807         qevent_block->mlxsw_sp = mlxsw_sp;
1808         return qevent_block;
1809 }
1810
1811 static void
1812 mlxsw_sp_qevent_block_destroy(struct mlxsw_sp_qevent_block *qevent_block)
1813 {
1814         WARN_ON(!list_empty(&qevent_block->binding_list));
1815         WARN_ON(!list_empty(&qevent_block->mall_entry_list));
1816         kfree(qevent_block);
1817 }
1818
1819 static void mlxsw_sp_qevent_block_release(void *cb_priv)
1820 {
1821         struct mlxsw_sp_qevent_block *qevent_block = cb_priv;
1822
1823         mlxsw_sp_qevent_block_destroy(qevent_block);
1824 }
1825
1826 static struct mlxsw_sp_qevent_binding *
1827 mlxsw_sp_qevent_binding_create(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, int tclass_num,
1828                                enum mlxsw_sp_span_trigger span_trigger)
1829 {
1830         struct mlxsw_sp_qevent_binding *binding;
1831
1832         binding = kzalloc(sizeof(*binding), GFP_KERNEL);
1833         if (!binding)
1834                 return ERR_PTR(-ENOMEM);
1835
1836         binding->mlxsw_sp_port = mlxsw_sp_port;
1837         binding->handle = handle;
1838         binding->tclass_num = tclass_num;
1839         binding->span_trigger = span_trigger;
1840         return binding;
1841 }
1842
1843 static void
1844 mlxsw_sp_qevent_binding_destroy(struct mlxsw_sp_qevent_binding *binding)
1845 {
1846         kfree(binding);
1847 }
1848
1849 static struct mlxsw_sp_qevent_binding *
1850 mlxsw_sp_qevent_binding_lookup(struct mlxsw_sp_qevent_block *block,
1851                                struct mlxsw_sp_port *mlxsw_sp_port,
1852                                u32 handle,
1853                                enum mlxsw_sp_span_trigger span_trigger)
1854 {
1855         struct mlxsw_sp_qevent_binding *qevent_binding;
1856
1857         list_for_each_entry(qevent_binding, &block->binding_list, list)
1858                 if (qevent_binding->mlxsw_sp_port == mlxsw_sp_port &&
1859                     qevent_binding->handle == handle &&
1860                     qevent_binding->span_trigger == span_trigger)
1861                         return qevent_binding;
1862         return NULL;
1863 }
1864
1865 static int mlxsw_sp_setup_tc_block_qevent_bind(struct mlxsw_sp_port *mlxsw_sp_port,
1866                                                struct flow_block_offload *f,
1867                                                enum mlxsw_sp_span_trigger span_trigger)
1868 {
1869         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1870         struct mlxsw_sp_qevent_binding *qevent_binding;
1871         struct mlxsw_sp_qevent_block *qevent_block;
1872         struct flow_block_cb *block_cb;
1873         struct mlxsw_sp_qdisc *qdisc;
1874         bool register_block = false;
1875         int err;
1876
1877         block_cb = flow_block_cb_lookup(f->block, mlxsw_sp_qevent_block_cb, mlxsw_sp);
1878         if (!block_cb) {
1879                 qevent_block = mlxsw_sp_qevent_block_create(mlxsw_sp, f->net);
1880                 if (!qevent_block)
1881                         return -ENOMEM;
1882                 block_cb = flow_block_cb_alloc(mlxsw_sp_qevent_block_cb, mlxsw_sp, qevent_block,
1883                                                mlxsw_sp_qevent_block_release);
1884                 if (IS_ERR(block_cb)) {
1885                         mlxsw_sp_qevent_block_destroy(qevent_block);
1886                         return PTR_ERR(block_cb);
1887                 }
1888                 register_block = true;
1889         } else {
1890                 qevent_block = flow_block_cb_priv(block_cb);
1891         }
1892         flow_block_cb_incref(block_cb);
1893
1894         qdisc = mlxsw_sp_qdisc_find_by_handle(mlxsw_sp_port, f->sch->handle);
1895         if (!qdisc) {
1896                 NL_SET_ERR_MSG(f->extack, "Qdisc not offloaded");
1897                 err = -ENOENT;
1898                 goto err_find_qdisc;
1899         }
1900
1901         if (WARN_ON(mlxsw_sp_qevent_binding_lookup(qevent_block, mlxsw_sp_port, f->sch->handle,
1902                                                    span_trigger))) {
1903                 err = -EEXIST;
1904                 goto err_binding_exists;
1905         }
1906
1907         qevent_binding = mlxsw_sp_qevent_binding_create(mlxsw_sp_port, f->sch->handle,
1908                                                         qdisc->tclass_num, span_trigger);
1909         if (IS_ERR(qevent_binding)) {
1910                 err = PTR_ERR(qevent_binding);
1911                 goto err_binding_create;
1912         }
1913
1914         err = mlxsw_sp_qevent_binding_configure(qevent_block, qevent_binding);
1915         if (err)
1916                 goto err_binding_configure;
1917
1918         list_add(&qevent_binding->list, &qevent_block->binding_list);
1919
1920         if (register_block) {
1921                 flow_block_cb_add(block_cb, f);
1922                 list_add_tail(&block_cb->driver_list, &mlxsw_sp_qevent_block_cb_list);
1923         }
1924
1925         return 0;
1926
1927 err_binding_configure:
1928         mlxsw_sp_qevent_binding_destroy(qevent_binding);
1929 err_binding_create:
1930 err_binding_exists:
1931 err_find_qdisc:
1932         if (!flow_block_cb_decref(block_cb))
1933                 flow_block_cb_free(block_cb);
1934         return err;
1935 }
1936
1937 static void mlxsw_sp_setup_tc_block_qevent_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
1938                                                   struct flow_block_offload *f,
1939                                                   enum mlxsw_sp_span_trigger span_trigger)
1940 {
1941         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1942         struct mlxsw_sp_qevent_binding *qevent_binding;
1943         struct mlxsw_sp_qevent_block *qevent_block;
1944         struct flow_block_cb *block_cb;
1945
1946         block_cb = flow_block_cb_lookup(f->block, mlxsw_sp_qevent_block_cb, mlxsw_sp);
1947         if (!block_cb)
1948                 return;
1949         qevent_block = flow_block_cb_priv(block_cb);
1950
1951         qevent_binding = mlxsw_sp_qevent_binding_lookup(qevent_block, mlxsw_sp_port, f->sch->handle,
1952                                                         span_trigger);
1953         if (!qevent_binding)
1954                 return;
1955
1956         list_del(&qevent_binding->list);
1957         mlxsw_sp_qevent_binding_deconfigure(qevent_block, qevent_binding);
1958         mlxsw_sp_qevent_binding_destroy(qevent_binding);
1959
1960         if (!flow_block_cb_decref(block_cb)) {
1961                 flow_block_cb_remove(block_cb, f);
1962                 list_del(&block_cb->driver_list);
1963         }
1964 }
1965
1966 static int mlxsw_sp_setup_tc_block_qevent(struct mlxsw_sp_port *mlxsw_sp_port,
1967                                           struct flow_block_offload *f,
1968                                           enum mlxsw_sp_span_trigger span_trigger)
1969 {
1970         f->driver_block_list = &mlxsw_sp_qevent_block_cb_list;
1971
1972         switch (f->command) {
1973         case FLOW_BLOCK_BIND:
1974                 return mlxsw_sp_setup_tc_block_qevent_bind(mlxsw_sp_port, f, span_trigger);
1975         case FLOW_BLOCK_UNBIND:
1976                 mlxsw_sp_setup_tc_block_qevent_unbind(mlxsw_sp_port, f, span_trigger);
1977                 return 0;
1978         default:
1979                 return -EOPNOTSUPP;
1980         }
1981 }
1982
1983 int mlxsw_sp_setup_tc_block_qevent_early_drop(struct mlxsw_sp_port *mlxsw_sp_port,
1984                                               struct flow_block_offload *f)
1985 {
1986         return mlxsw_sp_setup_tc_block_qevent(mlxsw_sp_port, f, MLXSW_SP_SPAN_TRIGGER_EARLY_DROP);
1987 }
1988
1989 int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port)
1990 {
1991         struct mlxsw_sp_qdisc_state *qdisc_state;
1992
1993         qdisc_state = kzalloc(sizeof(*qdisc_state), GFP_KERNEL);
1994         if (!qdisc_state)
1995                 return -ENOMEM;
1996
1997         mutex_init(&qdisc_state->lock);
1998         qdisc_state->root_qdisc.prio_bitmap = 0xff;
1999         qdisc_state->root_qdisc.tclass_num = MLXSW_SP_PORT_DEFAULT_TCLASS;
2000         mlxsw_sp_port->qdisc = qdisc_state;
2001         return 0;
2002 }
2003
2004 void mlxsw_sp_tc_qdisc_fini(struct mlxsw_sp_port *mlxsw_sp_port)
2005 {
2006         mutex_destroy(&mlxsw_sp_port->qdisc->lock);
2007         kfree(mlxsw_sp_port->qdisc);
2008 }