xref: /linux/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip Sparx5 Switch driver
3  *
4  * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
5  */
6 
7 #include <net/pkt_cls.h>
8 
9 #include "sparx5_main.h"
10 #include "sparx5_qos.h"
11 
12 enum sparx5_tas_link_speed {
13 	TAS_SPEED_NO_GB,
14 	TAS_SPEED_10,
15 	TAS_SPEED_100,
16 	TAS_SPEED_1000,
17 	TAS_SPEED_2500,
18 	TAS_SPEED_5000,
19 	TAS_SPEED_10000,
20 	TAS_SPEED_25000,
21 };
22 
23 /* Calculate new base_time based on cycle_time.
24  *
25  * The hardware requires a base_time that is always in the future.
26  * We define threshold_time as current_time + (2 * cycle_time).
27  * If base_time is below threshold_time this function recalculates it to be in
28  * the interval:
29  * threshold_time <= base_time < (threshold_time + cycle_time)
30  *
31  * A very simple algorithm could be like this:
32  * new_base_time = org_base_time + N * cycle_time
33  * using the lowest N so (new_base_time >= threshold_time
34  */
sparx5_new_base_time(struct sparx5 * sparx5,const u32 cycle_time,const ktime_t org_base_time,ktime_t * new_base_time)35 void sparx5_new_base_time(struct sparx5 *sparx5, const u32 cycle_time,
36 			  const ktime_t org_base_time, ktime_t *new_base_time)
37 {
38 	ktime_t current_time, threshold_time, new_time;
39 	struct timespec64 ts;
40 	u64 nr_of_cycles_p2;
41 	u64 nr_of_cycles;
42 	u64 diff_time;
43 
44 	new_time = org_base_time;
45 
46 	sparx5_ptp_gettime64(&sparx5->phc[SPARX5_PHC_PORT].info, &ts);
47 	current_time = timespec64_to_ktime(ts);
48 	threshold_time = current_time + (2 * cycle_time);
49 	diff_time = threshold_time - new_time;
50 	nr_of_cycles = div_u64(diff_time, cycle_time);
51 	nr_of_cycles_p2 = 1; /* Use 2^0 as start value */
52 
53 	if (new_time >= threshold_time) {
54 		*new_base_time = new_time;
55 		return;
56 	}
57 
58 	/* Calculate the smallest power of 2 (nr_of_cycles_p2)
59 	 * that is larger than nr_of_cycles.
60 	 */
61 	while (nr_of_cycles_p2 < nr_of_cycles)
62 		nr_of_cycles_p2 <<= 1; /* Next (higher) power of 2 */
63 
64 	/* Add as big chunks (power of 2 * cycle_time)
65 	 * as possible for each power of 2
66 	 */
67 	while (nr_of_cycles_p2) {
68 		if (new_time < threshold_time) {
69 			new_time += cycle_time * nr_of_cycles_p2;
70 			while (new_time < threshold_time)
71 				new_time += cycle_time * nr_of_cycles_p2;
72 			new_time -= cycle_time * nr_of_cycles_p2;
73 		}
74 		nr_of_cycles_p2 >>= 1; /* Next (lower) power of 2 */
75 	}
76 	new_time += cycle_time;
77 	*new_base_time = new_time;
78 }
79 
80 /* Max rates for leak groups */
81 static const u32 spx5_hsch_max_group_rate[SPX5_HSCH_LEAK_GRP_CNT] = {
82 	1048568, /*  1.049 Gbps */
83 	2621420, /*  2.621 Gbps */
84 	10485680, /* 10.486 Gbps */
85 	26214200 /* 26.214 Gbps */
86 };
87 
sparx5_get_hsch_max_group_rate(int grp)88 u32 sparx5_get_hsch_max_group_rate(int grp)
89 {
90 	return spx5_hsch_max_group_rate[grp];
91 }
92 
93 static struct sparx5_layer layers[SPX5_HSCH_LAYER_CNT];
94 
sparx5_lg_get_leak_time(struct sparx5 * sparx5,u32 layer,u32 group)95 static u32 sparx5_lg_get_leak_time(struct sparx5 *sparx5, u32 layer, u32 group)
96 {
97 	u32 value;
98 
99 	value = spx5_rd(sparx5, HSCH_HSCH_TIMER_CFG(layer, group));
100 	return HSCH_HSCH_TIMER_CFG_LEAK_TIME_GET(value);
101 }
102 
sparx5_lg_set_leak_time(struct sparx5 * sparx5,u32 layer,u32 group,u32 leak_time)103 static void sparx5_lg_set_leak_time(struct sparx5 *sparx5, u32 layer, u32 group,
104 				    u32 leak_time)
105 {
106 	spx5_wr(HSCH_HSCH_TIMER_CFG_LEAK_TIME_SET(leak_time), sparx5,
107 		HSCH_HSCH_TIMER_CFG(layer, group));
108 }
109 
sparx5_lg_get_first(struct sparx5 * sparx5,u32 layer,u32 group)110 static u32 sparx5_lg_get_first(struct sparx5 *sparx5, u32 layer, u32 group)
111 {
112 	u32 value;
113 
114 	value = spx5_rd(sparx5, HSCH_HSCH_LEAK_CFG(layer, group));
115 	return HSCH_HSCH_LEAK_CFG_LEAK_FIRST_GET(value);
116 }
117 
sparx5_lg_get_next(struct sparx5 * sparx5,u32 layer,u32 group,u32 idx)118 static u32 sparx5_lg_get_next(struct sparx5 *sparx5, u32 layer, u32 group,
119 			      u32 idx)
120 
121 {
122 	u32 value;
123 
124 	value = spx5_rd(sparx5, HSCH_SE_CONNECT(idx));
125 	return HSCH_SE_CONNECT_SE_LEAK_LINK_GET(value);
126 }
127 
sparx5_lg_get_last(struct sparx5 * sparx5,u32 layer,u32 group)128 static u32 sparx5_lg_get_last(struct sparx5 *sparx5, u32 layer, u32 group)
129 {
130 	u32 itr, next;
131 
132 	itr = sparx5_lg_get_first(sparx5, layer, group);
133 
134 	for (;;) {
135 		next = sparx5_lg_get_next(sparx5, layer, group, itr);
136 		if (itr == next)
137 			return itr;
138 
139 		itr = next;
140 	}
141 }
142 
sparx5_lg_is_last(struct sparx5 * sparx5,u32 layer,u32 group,u32 idx)143 static bool sparx5_lg_is_last(struct sparx5 *sparx5, u32 layer, u32 group,
144 			      u32 idx)
145 {
146 	return idx == sparx5_lg_get_next(sparx5, layer, group, idx);
147 }
148 
sparx5_lg_is_first(struct sparx5 * sparx5,u32 layer,u32 group,u32 idx)149 static bool sparx5_lg_is_first(struct sparx5 *sparx5, u32 layer, u32 group,
150 			       u32 idx)
151 {
152 	return idx == sparx5_lg_get_first(sparx5, layer, group);
153 }
154 
sparx5_lg_is_empty(struct sparx5 * sparx5,u32 layer,u32 group)155 static bool sparx5_lg_is_empty(struct sparx5 *sparx5, u32 layer, u32 group)
156 {
157 	return sparx5_lg_get_leak_time(sparx5, layer, group) == 0;
158 }
159 
sparx5_lg_is_singular(struct sparx5 * sparx5,u32 layer,u32 group)160 static bool sparx5_lg_is_singular(struct sparx5 *sparx5, u32 layer, u32 group)
161 {
162 	if (sparx5_lg_is_empty(sparx5, layer, group))
163 		return false;
164 
165 	return sparx5_lg_get_first(sparx5, layer, group) ==
166 	       sparx5_lg_get_last(sparx5, layer, group);
167 }
168 
sparx5_lg_enable(struct sparx5 * sparx5,u32 layer,u32 group,u32 leak_time)169 static void sparx5_lg_enable(struct sparx5 *sparx5, u32 layer, u32 group,
170 			     u32 leak_time)
171 {
172 	sparx5_lg_set_leak_time(sparx5, layer, group, leak_time);
173 }
174 
sparx5_lg_disable(struct sparx5 * sparx5,u32 layer,u32 group)175 static void sparx5_lg_disable(struct sparx5 *sparx5, u32 layer, u32 group)
176 {
177 	sparx5_lg_set_leak_time(sparx5, layer, group, 0);
178 }
179 
sparx5_lg_get_group_by_index(struct sparx5 * sparx5,u32 layer,u32 idx,u32 * group)180 static int sparx5_lg_get_group_by_index(struct sparx5 *sparx5, u32 layer,
181 					u32 idx, u32 *group)
182 {
183 	u32 itr, next;
184 	int i;
185 
186 	for (i = 0; i < SPX5_HSCH_LEAK_GRP_CNT; i++) {
187 		if (sparx5_lg_is_empty(sparx5, layer, i))
188 			continue;
189 
190 		itr = sparx5_lg_get_first(sparx5, layer, i);
191 
192 		for (;;) {
193 			next = sparx5_lg_get_next(sparx5, layer, i, itr);
194 
195 			if (itr == idx) {
196 				*group = i;
197 				return 0; /* Found it */
198 			}
199 			if (itr == next)
200 				break; /* Was not found */
201 
202 			itr = next;
203 		}
204 	}
205 
206 	return -1;
207 }
208 
sparx5_lg_get_group_by_rate(u32 layer,u32 rate,u32 * group)209 static int sparx5_lg_get_group_by_rate(u32 layer, u32 rate, u32 *group)
210 {
211 	struct sparx5_layer *l = &layers[layer];
212 	struct sparx5_lg *lg;
213 	u32 i;
214 
215 	for (i = 0; i < SPX5_HSCH_LEAK_GRP_CNT; i++) {
216 		lg = &l->leak_groups[i];
217 		if (rate <= lg->max_rate) {
218 			*group = i;
219 			return 0;
220 		}
221 	}
222 
223 	return -1;
224 }
225 
sparx5_lg_get_adjacent(struct sparx5 * sparx5,u32 layer,u32 group,u32 idx,u32 * prev,u32 * next,u32 * first)226 static int sparx5_lg_get_adjacent(struct sparx5 *sparx5, u32 layer, u32 group,
227 				  u32 idx, u32 *prev, u32 *next, u32 *first)
228 {
229 	u32 itr;
230 
231 	*first = sparx5_lg_get_first(sparx5, layer, group);
232 	*prev = *first;
233 	*next = *first;
234 	itr = *first;
235 
236 	for (;;) {
237 		*next = sparx5_lg_get_next(sparx5, layer, group, itr);
238 
239 		if (itr == idx)
240 			return 0; /* Found it */
241 
242 		if (itr == *next)
243 			return -1; /* Was not found */
244 
245 		*prev = itr;
246 		itr = *next;
247 	}
248 
249 	return -1;
250 }
251 
sparx5_lg_conf_set(struct sparx5 * sparx5,u32 layer,u32 group,u32 se_first,u32 idx,u32 idx_next,bool empty)252 static int sparx5_lg_conf_set(struct sparx5 *sparx5, u32 layer, u32 group,
253 			      u32 se_first, u32 idx, u32 idx_next, bool empty)
254 {
255 	u32 leak_time = layers[layer].leak_groups[group].leak_time;
256 
257 	/* Stop leaking */
258 	sparx5_lg_disable(sparx5, layer, group);
259 
260 	if (empty)
261 		return 0;
262 
263 	/* Select layer */
264 	spx5_rmw(HSCH_HSCH_CFG_CFG_HSCH_LAYER_SET(layer),
265 		 HSCH_HSCH_CFG_CFG_HSCH_LAYER, sparx5, HSCH_HSCH_CFG_CFG);
266 
267 	/* Link elements */
268 	spx5_wr(HSCH_SE_CONNECT_SE_LEAK_LINK_SET(idx_next), sparx5,
269 		HSCH_SE_CONNECT(idx));
270 
271 	/* Set the first element. */
272 	spx5_rmw(HSCH_HSCH_LEAK_CFG_LEAK_FIRST_SET(se_first),
273 		 HSCH_HSCH_LEAK_CFG_LEAK_FIRST, sparx5,
274 		 HSCH_HSCH_LEAK_CFG(layer, group));
275 
276 	/* Start leaking */
277 	sparx5_lg_enable(sparx5, layer, group, leak_time);
278 
279 	return 0;
280 }
281 
sparx5_lg_del(struct sparx5 * sparx5,u32 layer,u32 group,u32 idx)282 static int sparx5_lg_del(struct sparx5 *sparx5, u32 layer, u32 group, u32 idx)
283 {
284 	u32 first, next, prev;
285 	bool empty = false;
286 
287 	/* idx *must* be present in the leak group */
288 	WARN_ON(sparx5_lg_get_adjacent(sparx5, layer, group, idx, &prev, &next,
289 				       &first) < 0);
290 
291 	if (sparx5_lg_is_singular(sparx5, layer, group)) {
292 		empty = true;
293 	} else if (sparx5_lg_is_last(sparx5, layer, group, idx)) {
294 		/* idx is removed, prev is now last */
295 		idx = prev;
296 		next = prev;
297 	} else if (sparx5_lg_is_first(sparx5, layer, group, idx)) {
298 		/* idx is removed and points to itself, first is next */
299 		first = next;
300 		next = idx;
301 	} else {
302 		/* Next is not touched */
303 		idx = prev;
304 	}
305 
306 	return sparx5_lg_conf_set(sparx5, layer, group, first, idx, next,
307 				  empty);
308 }
309 
sparx5_lg_add(struct sparx5 * sparx5,u32 layer,u32 new_group,u32 idx)310 static int sparx5_lg_add(struct sparx5 *sparx5, u32 layer, u32 new_group,
311 			 u32 idx)
312 {
313 	u32 first, next, old_group;
314 
315 	pr_debug("ADD: layer: %d, new_group: %d, idx: %d", layer, new_group,
316 		 idx);
317 
318 	/* Is this SE already shaping ? */
319 	if (sparx5_lg_get_group_by_index(sparx5, layer, idx, &old_group) >= 0) {
320 		if (old_group != new_group) {
321 			/* Delete from old group */
322 			sparx5_lg_del(sparx5, layer, old_group, idx);
323 		} else {
324 			/* Nothing to do here */
325 			return 0;
326 		}
327 	}
328 
329 	/* We always add to head of the list */
330 	first = idx;
331 
332 	if (sparx5_lg_is_empty(sparx5, layer, new_group))
333 		next = idx;
334 	else
335 		next = sparx5_lg_get_first(sparx5, layer, new_group);
336 
337 	return sparx5_lg_conf_set(sparx5, layer, new_group, first, idx, next,
338 				  false);
339 }
340 
sparx5_shaper_conf_set(struct sparx5_port * port,const struct sparx5_shaper * sh,u32 layer,u32 idx,u32 group)341 static int sparx5_shaper_conf_set(struct sparx5_port *port,
342 				  const struct sparx5_shaper *sh, u32 layer,
343 				  u32 idx, u32 group)
344 {
345 	int (*sparx5_lg_action)(struct sparx5 *, u32, u32, u32);
346 	struct sparx5 *sparx5 = port->sparx5;
347 
348 	if (!sh->rate && !sh->burst)
349 		sparx5_lg_action = &sparx5_lg_del;
350 	else
351 		sparx5_lg_action = &sparx5_lg_add;
352 
353 	/* Select layer */
354 	spx5_rmw(HSCH_HSCH_CFG_CFG_HSCH_LAYER_SET(layer),
355 		 HSCH_HSCH_CFG_CFG_HSCH_LAYER, sparx5, HSCH_HSCH_CFG_CFG);
356 
357 	/* Set frame mode */
358 	spx5_rmw(HSCH_SE_CFG_SE_FRM_MODE_SET(sh->mode), HSCH_SE_CFG_SE_FRM_MODE,
359 		 sparx5, HSCH_SE_CFG(idx));
360 
361 	/* Set committed rate and burst */
362 	spx5_wr(HSCH_CIR_CFG_CIR_RATE_SET(sh->rate) |
363 			HSCH_CIR_CFG_CIR_BURST_SET(sh->burst),
364 		sparx5, HSCH_CIR_CFG(idx));
365 
366 	/* This has to be done after the shaper configuration has been set */
367 	sparx5_lg_action(sparx5, layer, group, idx);
368 
369 	return 0;
370 }
371 
sparx5_weight_to_hw_cost(u32 weight_min,u32 weight)372 static u32 sparx5_weight_to_hw_cost(u32 weight_min, u32 weight)
373 {
374 	return ((((SPX5_DWRR_COST_MAX << 4) * weight_min / weight) + 8) >> 4) -
375 	       1;
376 }
377 
sparx5_dwrr_conf_set(struct sparx5_port * port,struct sparx5_dwrr * dwrr)378 static int sparx5_dwrr_conf_set(struct sparx5_port *port,
379 				struct sparx5_dwrr *dwrr)
380 {
381 	u32 layer = is_sparx5(port->sparx5) ? 2 : 1;
382 	int i;
383 
384 	spx5_rmw(HSCH_HSCH_CFG_CFG_HSCH_LAYER_SET(layer) |
385 		 HSCH_HSCH_CFG_CFG_CFG_SE_IDX_SET(port->portno),
386 		 HSCH_HSCH_CFG_CFG_HSCH_LAYER | HSCH_HSCH_CFG_CFG_CFG_SE_IDX,
387 		 port->sparx5, HSCH_HSCH_CFG_CFG);
388 
389 	/* Number of *lower* indexes that are arbitrated dwrr */
390 	spx5_rmw(HSCH_SE_CFG_SE_DWRR_CNT_SET(dwrr->count),
391 		 HSCH_SE_CFG_SE_DWRR_CNT, port->sparx5,
392 		 HSCH_SE_CFG(port->portno));
393 
394 	for (i = 0; i < dwrr->count; i++) {
395 		spx5_rmw(HSCH_DWRR_ENTRY_DWRR_COST_SET(dwrr->cost[i]),
396 			 HSCH_DWRR_ENTRY_DWRR_COST, port->sparx5,
397 			 HSCH_DWRR_ENTRY(i));
398 	}
399 
400 	return 0;
401 }
402 
sparx5_leak_groups_init(struct sparx5 * sparx5)403 static int sparx5_leak_groups_init(struct sparx5 *sparx5)
404 {
405 	const struct sparx5_ops *ops = sparx5->data->ops;
406 	struct sparx5_layer *layer;
407 	u32 sys_clk_per_100ps;
408 	struct sparx5_lg *lg;
409 	u32 leak_time_us;
410 	int i, ii;
411 
412 	sys_clk_per_100ps = spx5_rd(sparx5, HSCH_SYS_CLK_PER);
413 
414 	for (i = 0; i < SPX5_HSCH_LAYER_CNT; i++) {
415 		layer = &layers[i];
416 		for (ii = 0; ii < SPX5_HSCH_LEAK_GRP_CNT; ii++) {
417 			lg = &layer->leak_groups[ii];
418 			lg->max_rate = ops->get_hsch_max_group_rate(i);
419 
420 			/* Calculate the leak time in us, to serve a maximum
421 			 * rate of 'max_rate' for this group
422 			 */
423 			leak_time_us = (SPX5_SE_RATE_MAX * 1000) / lg->max_rate;
424 
425 			/* Hardware wants leak time in ns */
426 			lg->leak_time = 1000 * leak_time_us;
427 
428 			/* Calculate resolution */
429 			lg->resolution = 1000 / leak_time_us;
430 
431 			/* Maximum number of shapers that can be served by
432 			 * this leak group
433 			 */
434 			lg->max_ses = (1000 * leak_time_us) / sys_clk_per_100ps;
435 
436 			/* Example:
437 			 * Wanted bandwidth is 100Mbit:
438 			 *
439 			 * 100 mbps can be served by leak group zero.
440 			 *
441 			 * leak_time is 125000 ns.
442 			 * resolution is: 8
443 			 *
444 			 * cir          = 100000 / 8 = 12500
445 			 * leaks_pr_sec = 125000 / 10^9 = 8000
446 			 * bw           = 12500 * 8000 = 10^8 (100 Mbit)
447 			 */
448 
449 			/* Disable by default - this also indicates an empty
450 			 * leak group
451 			 */
452 			sparx5_lg_disable(sparx5, i, ii);
453 		}
454 	}
455 
456 	return 0;
457 }
458 
sparx5_qos_init(struct sparx5 * sparx5)459 int sparx5_qos_init(struct sparx5 *sparx5)
460 {
461 	int ret;
462 
463 	ret = sparx5_leak_groups_init(sparx5);
464 	if (ret < 0)
465 		return ret;
466 
467 	ret = sparx5_dcb_init(sparx5);
468 	if (ret < 0)
469 		return ret;
470 
471 	sparx5_psfp_init(sparx5);
472 
473 	return 0;
474 }
475 
sparx5_tc_mqprio_add(struct net_device * ndev,u8 num_tc)476 int sparx5_tc_mqprio_add(struct net_device *ndev, u8 num_tc)
477 {
478 	int i;
479 
480 	if (num_tc != SPX5_PRIOS) {
481 		netdev_err(ndev, "Only %d traffic classes supported\n",
482 			   SPX5_PRIOS);
483 		return -EINVAL;
484 	}
485 
486 	netdev_set_num_tc(ndev, num_tc);
487 
488 	for (i = 0; i < num_tc; i++)
489 		netdev_set_tc_queue(ndev, i, 1, i);
490 
491 	netdev_dbg(ndev, "dev->num_tc %u dev->real_num_tx_queues %u\n",
492 		   ndev->num_tc, ndev->real_num_tx_queues);
493 
494 	return 0;
495 }
496 
sparx5_tc_mqprio_del(struct net_device * ndev)497 int sparx5_tc_mqprio_del(struct net_device *ndev)
498 {
499 	netdev_reset_tc(ndev);
500 
501 	netdev_dbg(ndev, "dev->num_tc %u dev->real_num_tx_queues %u\n",
502 		   ndev->num_tc, ndev->real_num_tx_queues);
503 
504 	return 0;
505 }
506 
sparx5_tc_tbf_add(struct sparx5_port * port,struct tc_tbf_qopt_offload_replace_params * params,u32 layer,u32 idx)507 int sparx5_tc_tbf_add(struct sparx5_port *port,
508 		      struct tc_tbf_qopt_offload_replace_params *params,
509 		      u32 layer, u32 idx)
510 {
511 	struct sparx5_shaper sh = {
512 		.mode = SPX5_SE_MODE_DATARATE,
513 		.rate = div_u64(params->rate.rate_bytes_ps, 1000) * 8,
514 		.burst = params->max_size,
515 	};
516 	struct sparx5_lg *lg;
517 	u32 group;
518 
519 	/* Find suitable group for this se */
520 	if (sparx5_lg_get_group_by_rate(layer, sh.rate, &group) < 0) {
521 		pr_debug("Could not find leak group for se with rate: %d",
522 			 sh.rate);
523 		return -EINVAL;
524 	}
525 
526 	lg = &layers[layer].leak_groups[group];
527 
528 	pr_debug("Found matching group (speed: %d)\n", lg->max_rate);
529 
530 	if (sh.rate < SPX5_SE_RATE_MIN || sh.burst < SPX5_SE_BURST_MIN)
531 		return -EINVAL;
532 
533 	/* Calculate committed rate and burst */
534 	sh.rate = DIV_ROUND_UP(sh.rate, lg->resolution);
535 	sh.burst = DIV_ROUND_UP(sh.burst, SPX5_SE_BURST_UNIT);
536 
537 	if (sh.rate > SPX5_SE_RATE_MAX || sh.burst > SPX5_SE_BURST_MAX)
538 		return -EINVAL;
539 
540 	return sparx5_shaper_conf_set(port, &sh, layer, idx, group);
541 }
542 
sparx5_tc_tbf_del(struct sparx5_port * port,u32 layer,u32 idx)543 int sparx5_tc_tbf_del(struct sparx5_port *port, u32 layer, u32 idx)
544 {
545 	struct sparx5_shaper sh = {0};
546 	u32 group;
547 
548 	sparx5_lg_get_group_by_index(port->sparx5, layer, idx, &group);
549 
550 	return sparx5_shaper_conf_set(port, &sh, layer, idx, group);
551 }
552 
sparx5_tc_ets_add(struct sparx5_port * port,struct tc_ets_qopt_offload_replace_params * params)553 int sparx5_tc_ets_add(struct sparx5_port *port,
554 		      struct tc_ets_qopt_offload_replace_params *params)
555 {
556 	struct sparx5_dwrr dwrr = {0};
557 	/* Minimum weight for each iteration */
558 	unsigned int w_min = 100;
559 	int i;
560 
561 	/* Find minimum weight for all dwrr bands */
562 	for (i = 0; i < SPX5_PRIOS; i++) {
563 		if (params->quanta[i] == 0)
564 			continue;
565 		w_min = min(w_min, params->weights[i]);
566 	}
567 
568 	for (i = 0; i < SPX5_PRIOS; i++) {
569 		/* Strict band; skip */
570 		if (params->quanta[i] == 0)
571 			continue;
572 
573 		dwrr.count++;
574 
575 		/* On the sparx5, bands with higher indexes are preferred and
576 		 * arbitrated strict. Strict bands are put in the lower indexes,
577 		 * by tc, so we reverse the bands here.
578 		 *
579 		 * Also convert the weight to something the hardware
580 		 * understands.
581 		 */
582 		dwrr.cost[SPX5_PRIOS - i - 1] =
583 			sparx5_weight_to_hw_cost(w_min, params->weights[i]);
584 	}
585 
586 	return sparx5_dwrr_conf_set(port, &dwrr);
587 }
588 
sparx5_tc_ets_del(struct sparx5_port * port)589 int sparx5_tc_ets_del(struct sparx5_port *port)
590 {
591 	struct sparx5_dwrr dwrr = {0};
592 
593 	return sparx5_dwrr_conf_set(port, &dwrr);
594 }
595 
sparx5_tas_speed(struct sparx5_port * port,int speed)596 void sparx5_tas_speed(struct sparx5_port *port, int speed)
597 {
598 	struct sparx5 *sparx5 = port->sparx5;
599 	u8 spd;
600 
601 	switch (speed) {
602 	case SPEED_10:
603 		spd = TAS_SPEED_10;
604 		break;
605 	case SPEED_100:
606 		spd = TAS_SPEED_100;
607 		break;
608 	case SPEED_1000:
609 		spd = TAS_SPEED_1000;
610 		break;
611 	case SPEED_2500:
612 		spd = TAS_SPEED_2500;
613 		break;
614 	case SPEED_5000:
615 		spd = TAS_SPEED_5000;
616 		break;
617 	case SPEED_10000:
618 		spd = TAS_SPEED_10000;
619 		break;
620 	case SPEED_25000:
621 		spd = TAS_SPEED_25000;
622 		break;
623 	default:
624 		netdev_err(port->ndev, "TAS: Unsupported speed: %d\n", speed);
625 		return;
626 	}
627 
628 	spx5_rmw(HSCH_TAS_PROFILE_CONFIG_LINK_SPEED_SET(spd),
629 		 HSCH_TAS_PROFILE_CONFIG_LINK_SPEED,
630 		 sparx5,
631 		 HSCH_TAS_PROFILE_CONFIG(port->portno));
632 }
633