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