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