Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <string.h>
7 : :
8 : : #include <rte_common.h>
9 : : #include <rte_log.h>
10 : : #include <rte_malloc.h>
11 : : #include <rte_cycles.h>
12 : : #include <rte_prefetch.h>
13 : : #include <rte_branch_prediction.h>
14 : : #include <rte_mbuf.h>
15 : : #include <rte_bitmap.h>
16 : : #include <rte_reciprocal.h>
17 : :
18 : : #include "rte_sched.h"
19 : : #include "rte_sched_log.h"
20 : : #include "rte_sched_common.h"
21 : :
22 : : #include "rte_approx.h"
23 : :
24 : :
25 : : #ifdef __INTEL_COMPILER
26 : : #pragma warning(disable:2259) /* conversion may lose significant bits */
27 : : #endif
28 : :
29 : : #ifndef RTE_SCHED_PORT_N_GRINDERS
30 : : #define RTE_SCHED_PORT_N_GRINDERS 8
31 : : #endif
32 : :
33 : : #define RTE_SCHED_TB_RATE_CONFIG_ERR (1e-7)
34 : : #define RTE_SCHED_WRR_SHIFT 3
35 : : #define RTE_SCHED_MAX_QUEUES_PER_TC RTE_SCHED_BE_QUEUES_PER_PIPE
36 : : #define RTE_SCHED_GRINDER_PCACHE_SIZE (64 / RTE_SCHED_QUEUES_PER_PIPE)
37 : : #define RTE_SCHED_PIPE_INVALID UINT32_MAX
38 : : #define RTE_SCHED_BMP_POS_INVALID UINT32_MAX
39 : :
40 : : /* Scaling for cycles_per_byte calculation
41 : : * Chosen so that minimum rate is 480 bit/sec
42 : : */
43 : : #define RTE_SCHED_TIME_SHIFT 8
44 : :
45 : : struct rte_sched_pipe_profile {
46 : : /* Token bucket (TB) */
47 : : uint64_t tb_period;
48 : : uint64_t tb_credits_per_period;
49 : : uint64_t tb_size;
50 : :
51 : : /* Pipe traffic classes */
52 : : uint64_t tc_period;
53 : : uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
54 : : uint8_t tc_ov_weight;
55 : :
56 : : /* Pipe best-effort traffic class queues */
57 : : uint8_t wrr_cost[RTE_SCHED_BE_QUEUES_PER_PIPE];
58 : : };
59 : :
60 : : struct rte_sched_pipe {
61 : : /* Token bucket (TB) */
62 : : uint64_t tb_time; /* time of last update */
63 : : uint64_t tb_credits;
64 : :
65 : : /* Pipe profile and flags */
66 : : uint32_t profile;
67 : :
68 : : /* Traffic classes (TCs) */
69 : : uint64_t tc_time; /* time of next update */
70 : : uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
71 : :
72 : : /* Weighted Round Robin (WRR) */
73 : : uint8_t wrr_tokens[RTE_SCHED_BE_QUEUES_PER_PIPE];
74 : :
75 : : /* TC oversubscription */
76 : : uint64_t tc_ov_credits;
77 : : uint8_t tc_ov_period_id;
78 : : } __rte_cache_aligned;
79 : :
80 : : struct rte_sched_queue {
81 : : uint16_t qw;
82 : : uint16_t qr;
83 : : };
84 : :
85 : : struct rte_sched_queue_extra {
86 : : struct rte_sched_queue_stats stats;
87 : : union {
88 : : struct rte_red red;
89 : : struct rte_pie pie;
90 : : };
91 : : };
92 : :
93 : : enum grinder_state {
94 : : e_GRINDER_PREFETCH_PIPE = 0,
95 : : e_GRINDER_PREFETCH_TC_QUEUE_ARRAYS,
96 : : e_GRINDER_PREFETCH_MBUF,
97 : : e_GRINDER_READ_MBUF
98 : : };
99 : :
100 : : struct rte_sched_subport_profile {
101 : : /* Token bucket (TB) */
102 : : uint64_t tb_period;
103 : : uint64_t tb_credits_per_period;
104 : : uint64_t tb_size;
105 : :
106 : : uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
107 : : uint64_t tc_period;
108 : : };
109 : :
110 : : struct rte_sched_grinder {
111 : : /* Pipe cache */
112 : : uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
113 : : uint32_t pcache_qindex[RTE_SCHED_GRINDER_PCACHE_SIZE];
114 : : uint32_t pcache_w;
115 : : uint32_t pcache_r;
116 : :
117 : : /* Current pipe */
118 : : enum grinder_state state;
119 : : uint32_t productive;
120 : : uint32_t pindex;
121 : : struct rte_sched_subport *subport;
122 : : struct rte_sched_subport_profile *subport_params;
123 : : struct rte_sched_pipe *pipe;
124 : : struct rte_sched_pipe_profile *pipe_params;
125 : :
126 : : /* TC cache */
127 : : uint8_t tccache_qmask[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
128 : : uint32_t tccache_qindex[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
129 : : uint32_t tccache_w;
130 : : uint32_t tccache_r;
131 : :
132 : : /* Current TC */
133 : : uint32_t tc_index;
134 : : struct rte_sched_queue *queue[RTE_SCHED_MAX_QUEUES_PER_TC];
135 : : struct rte_mbuf **qbase[RTE_SCHED_MAX_QUEUES_PER_TC];
136 : : uint32_t qindex[RTE_SCHED_MAX_QUEUES_PER_TC];
137 : : uint16_t qsize;
138 : : uint32_t qmask;
139 : : uint32_t qpos;
140 : : struct rte_mbuf *pkt;
141 : :
142 : : /* WRR */
143 : : uint16_t wrr_tokens[RTE_SCHED_BE_QUEUES_PER_PIPE];
144 : : uint16_t wrr_mask[RTE_SCHED_BE_QUEUES_PER_PIPE];
145 : : uint8_t wrr_cost[RTE_SCHED_BE_QUEUES_PER_PIPE];
146 : : };
147 : :
148 : : struct rte_sched_subport {
149 : : /* Token bucket (TB) */
150 : : uint64_t tb_time; /* time of last update */
151 : : uint64_t tb_credits;
152 : :
153 : : /* Traffic classes (TCs) */
154 : : uint64_t tc_time; /* time of next update */
155 : : uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
156 : :
157 : : /* TC oversubscription */
158 : : uint64_t tc_ov_wm;
159 : : uint64_t tc_ov_wm_min;
160 : : uint64_t tc_ov_wm_max;
161 : : uint8_t tc_ov_period_id;
162 : : uint8_t tc_ov;
163 : : uint32_t tc_ov_n;
164 : : double tc_ov_rate;
165 : :
166 : : /* Statistics */
167 : : struct rte_sched_subport_stats stats __rte_cache_aligned;
168 : :
169 : : /* subport profile */
170 : : uint32_t profile;
171 : : /* Subport pipes */
172 : : uint32_t n_pipes_per_subport_enabled;
173 : : uint32_t n_pipe_profiles;
174 : : uint32_t n_max_pipe_profiles;
175 : :
176 : : /* Pipe best-effort TC rate */
177 : : uint64_t pipe_tc_be_rate_max;
178 : :
179 : : /* Pipe queues size */
180 : : uint16_t qsize[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
181 : :
182 : : bool cman_enabled;
183 : : enum rte_sched_cman_mode cman;
184 : :
185 : : union {
186 : : struct rte_red_config red_config[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE][RTE_COLORS];
187 : : struct rte_pie_config pie_config[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
188 : : };
189 : :
190 : : /* Scheduling loop detection */
191 : : uint32_t pipe_loop;
192 : : uint32_t pipe_exhaustion;
193 : :
194 : : /* Bitmap */
195 : : struct rte_bitmap *bmp;
196 : : uint32_t grinder_base_bmp_pos[RTE_SCHED_PORT_N_GRINDERS] __rte_aligned_16;
197 : :
198 : : /* Grinders */
199 : : struct rte_sched_grinder grinder[RTE_SCHED_PORT_N_GRINDERS];
200 : : uint32_t busy_grinders;
201 : :
202 : : /* Queue base calculation */
203 : : uint32_t qsize_add[RTE_SCHED_QUEUES_PER_PIPE];
204 : : uint32_t qsize_sum;
205 : :
206 : : /* TC oversubscription activation */
207 : : int tc_ov_enabled;
208 : :
209 : : struct rte_sched_pipe *pipe;
210 : : struct rte_sched_queue *queue;
211 : : struct rte_sched_queue_extra *queue_extra;
212 : : struct rte_sched_pipe_profile *pipe_profiles;
213 : : uint8_t *bmp_array;
214 : : struct rte_mbuf **queue_array;
215 : : uint8_t memory[0] __rte_cache_aligned;
216 : : } __rte_cache_aligned;
217 : :
218 : : struct rte_sched_port {
219 : : /* User parameters */
220 : : uint32_t n_subports_per_port;
221 : : uint32_t n_pipes_per_subport;
222 : : uint32_t n_pipes_per_subport_log2;
223 : : uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
224 : : uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
225 : : uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
226 : : uint32_t n_subport_profiles;
227 : : uint32_t n_max_subport_profiles;
228 : : uint64_t rate;
229 : : uint32_t mtu;
230 : : uint32_t frame_overhead;
231 : : int socket;
232 : :
233 : : /* Timing */
234 : : uint64_t time_cpu_cycles; /* Current CPU time measured in CPU cycles */
235 : : uint64_t time_cpu_bytes; /* Current CPU time measured in bytes */
236 : : uint64_t time; /* Current NIC TX time measured in bytes */
237 : : struct rte_reciprocal inv_cycles_per_byte; /* CPU cycles per byte */
238 : : uint64_t cycles_per_byte;
239 : :
240 : : /* Grinders */
241 : : struct rte_mbuf **pkts_out;
242 : : uint32_t n_pkts_out;
243 : : uint32_t subport_id;
244 : :
245 : : /* Large data structures */
246 : : struct rte_sched_subport_profile *subport_profiles;
247 : : struct rte_sched_subport *subports[0] __rte_cache_aligned;
248 : : } __rte_cache_aligned;
249 : :
250 : : enum rte_sched_subport_array {
251 : : e_RTE_SCHED_SUBPORT_ARRAY_PIPE = 0,
252 : : e_RTE_SCHED_SUBPORT_ARRAY_QUEUE,
253 : : e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA,
254 : : e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES,
255 : : e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY,
256 : : e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY,
257 : : e_RTE_SCHED_SUBPORT_ARRAY_TOTAL,
258 : : };
259 : :
260 : : static inline uint32_t
261 : : rte_sched_subport_pipe_queues(struct rte_sched_subport *subport)
262 : : {
263 : 3 : return RTE_SCHED_QUEUES_PER_PIPE * subport->n_pipes_per_subport_enabled;
264 : : }
265 : :
266 : : static inline struct rte_mbuf **
267 : : rte_sched_subport_pipe_qbase(struct rte_sched_subport *subport, uint32_t qindex)
268 : : {
269 : 16391 : uint32_t pindex = qindex >> 4;
270 : 16391 : uint32_t qpos = qindex & (RTE_SCHED_QUEUES_PER_PIPE - 1);
271 : :
272 : 16391 : return (subport->queue_array + pindex *
273 : 16391 : subport->qsize_sum + subport->qsize_add[qpos]);
274 : : }
275 : :
276 : : static inline uint16_t
277 : : rte_sched_subport_pipe_qsize(struct rte_sched_port *port,
278 : : struct rte_sched_subport *subport, uint32_t qindex)
279 : : {
280 : 16406 : uint32_t tc = port->pipe_tc[qindex & (RTE_SCHED_QUEUES_PER_PIPE - 1)];
281 : :
282 : 16406 : return subport->qsize[tc];
283 : : }
284 : :
285 : : static inline uint32_t
286 : : rte_sched_port_queues_per_port(struct rte_sched_port *port)
287 : : {
288 : : uint32_t n_queues = 0, i;
289 : :
290 [ + + ]: 2 : for (i = 0; i < port->n_subports_per_port; i++)
291 : 1 : n_queues += rte_sched_subport_pipe_queues(port->subports[i]);
292 : :
293 : : return n_queues;
294 : : }
295 : :
296 : : static inline uint16_t
297 : : rte_sched_port_pipe_queue(struct rte_sched_port *port, uint32_t traffic_class)
298 : : {
299 : 10 : uint16_t pipe_queue = port->pipe_queue[traffic_class];
300 : :
301 : : return pipe_queue;
302 : : }
303 : :
304 : : static inline uint8_t
305 : : rte_sched_port_pipe_tc(struct rte_sched_port *port, uint32_t qindex)
306 : : {
307 : 20 : uint8_t pipe_tc = port->pipe_tc[qindex & (RTE_SCHED_QUEUES_PER_PIPE - 1)];
308 : :
309 : : return pipe_tc;
310 : : }
311 : :
312 : : static inline uint8_t
313 : : rte_sched_port_tc_queue(struct rte_sched_port *port, uint32_t qindex)
314 : : {
315 : 10 : uint8_t tc_queue = port->tc_queue[qindex & (RTE_SCHED_QUEUES_PER_PIPE - 1)];
316 : :
317 : : return tc_queue;
318 : : }
319 : :
320 : : static int
321 : 1 : pipe_profile_check(struct rte_sched_pipe_params *params,
322 : : uint64_t rate, uint16_t *qsize)
323 : : {
324 : : uint32_t i;
325 : :
326 : : /* Pipe parameters */
327 [ - + ]: 1 : if (params == NULL) {
328 : 0 : SCHED_LOG(ERR,
329 : : "%s: Incorrect value for parameter params", __func__);
330 : 0 : return -EINVAL;
331 : : }
332 : :
333 : : /* TB rate: non-zero, not greater than port rate */
334 [ + - - + ]: 1 : if (params->tb_rate == 0 ||
335 : : params->tb_rate > rate) {
336 : 0 : SCHED_LOG(ERR,
337 : : "%s: Incorrect value for tb rate", __func__);
338 : 0 : return -EINVAL;
339 : : }
340 : :
341 : : /* TB size: non-zero */
342 [ - + ]: 1 : if (params->tb_size == 0) {
343 : 0 : SCHED_LOG(ERR,
344 : : "%s: Incorrect value for tb size", __func__);
345 : 0 : return -EINVAL;
346 : : }
347 : :
348 : : /* TC rate: non-zero if qsize non-zero, less than pipe rate */
349 [ + + ]: 14 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
350 [ - + - - : 13 : if ((qsize[i] == 0 && params->tc_rate[i] != 0) ||
+ - ]
351 [ + - - + ]: 13 : (qsize[i] != 0 && (params->tc_rate[i] == 0 ||
352 : : params->tc_rate[i] > params->tb_rate))) {
353 : 0 : SCHED_LOG(ERR,
354 : : "%s: Incorrect value for qsize or tc_rate", __func__);
355 : 0 : return -EINVAL;
356 : : }
357 : : }
358 : :
359 [ + - ]: 1 : if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0 ||
360 [ - + ]: 1 : qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
361 : 0 : SCHED_LOG(ERR,
362 : : "%s: Incorrect value for be traffic class rate", __func__);
363 : 0 : return -EINVAL;
364 : : }
365 : :
366 : : /* TC period: non-zero */
367 [ - + ]: 1 : if (params->tc_period == 0) {
368 : 0 : SCHED_LOG(ERR,
369 : : "%s: Incorrect value for tc period", __func__);
370 : 0 : return -EINVAL;
371 : : }
372 : :
373 : : /* Best effort tc oversubscription weight: non-zero */
374 [ - + ]: 1 : if (params->tc_ov_weight == 0) {
375 : 0 : SCHED_LOG(ERR,
376 : : "%s: Incorrect value for tc ov weight", __func__);
377 : 0 : return -EINVAL;
378 : : }
379 : :
380 : : /* Queue WRR weights: non-zero */
381 [ + + ]: 5 : for (i = 0; i < RTE_SCHED_BE_QUEUES_PER_PIPE; i++) {
382 [ - + ]: 4 : if (params->wrr_weights[i] == 0) {
383 : 0 : SCHED_LOG(ERR,
384 : : "%s: Incorrect value for wrr weight", __func__);
385 : 0 : return -EINVAL;
386 : : }
387 : : }
388 : :
389 : : return 0;
390 : : }
391 : :
392 : : static int
393 : 1 : subport_profile_check(struct rte_sched_subport_profile_params *params,
394 : : uint64_t rate)
395 : : {
396 : : uint32_t i;
397 : :
398 : : /* Check user parameters */
399 [ - + ]: 1 : if (params == NULL) {
400 : 0 : SCHED_LOG(ERR, "%s: "
401 : : "Incorrect value for parameter params", __func__);
402 : 0 : return -EINVAL;
403 : : }
404 : :
405 [ + - - + ]: 1 : if (params->tb_rate == 0 || params->tb_rate > rate) {
406 : 0 : SCHED_LOG(ERR, "%s: "
407 : : "Incorrect value for tb rate", __func__);
408 : 0 : return -EINVAL;
409 : : }
410 : :
411 [ - + ]: 1 : if (params->tb_size == 0) {
412 : 0 : SCHED_LOG(ERR, "%s: "
413 : : "Incorrect value for tb size", __func__);
414 : 0 : return -EINVAL;
415 : : }
416 : :
417 [ + + ]: 14 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
418 : 13 : uint64_t tc_rate = params->tc_rate[i];
419 : :
420 [ + - - + ]: 13 : if (tc_rate == 0 || (tc_rate > params->tb_rate)) {
421 : 0 : SCHED_LOG(ERR, "%s: "
422 : : "Incorrect value for tc rate", __func__);
423 : 0 : return -EINVAL;
424 : : }
425 : : }
426 : :
427 [ - + ]: 1 : if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
428 : 0 : SCHED_LOG(ERR, "%s: "
429 : : "Incorrect tc rate(best effort)", __func__);
430 : 0 : return -EINVAL;
431 : : }
432 : :
433 [ - + ]: 1 : if (params->tc_period == 0) {
434 : 0 : SCHED_LOG(ERR, "%s: "
435 : : "Incorrect value for tc period", __func__);
436 : 0 : return -EINVAL;
437 : : }
438 : :
439 : : return 0;
440 : : }
441 : :
442 : : static int
443 : 1 : rte_sched_port_check_params(struct rte_sched_port_params *params)
444 : : {
445 : : uint32_t i;
446 : :
447 [ - + ]: 1 : if (params == NULL) {
448 : 0 : SCHED_LOG(ERR,
449 : : "%s: Incorrect value for parameter params", __func__);
450 : 0 : return -EINVAL;
451 : : }
452 : :
453 : : /* socket */
454 [ - + ]: 1 : if (params->socket < 0) {
455 : 0 : SCHED_LOG(ERR,
456 : : "%s: Incorrect value for socket id", __func__);
457 : 0 : return -EINVAL;
458 : : }
459 : :
460 : : /* rate */
461 [ - + ]: 1 : if (params->rate == 0) {
462 : 0 : SCHED_LOG(ERR,
463 : : "%s: Incorrect value for rate", __func__);
464 : 0 : return -EINVAL;
465 : : }
466 : :
467 : : /* mtu */
468 [ - + ]: 1 : if (params->mtu == 0) {
469 : 0 : SCHED_LOG(ERR,
470 : : "%s: Incorrect value for mtu", __func__);
471 : 0 : return -EINVAL;
472 : : }
473 : :
474 : : /* n_subports_per_port: non-zero, limited to 16 bits, power of 2 */
475 [ + - ]: 1 : if (params->n_subports_per_port == 0 ||
476 : : params->n_subports_per_port > 1u << 16 ||
477 : : !rte_is_power_of_2(params->n_subports_per_port)) {
478 : 0 : SCHED_LOG(ERR,
479 : : "%s: Incorrect value for number of subports", __func__);
480 : 0 : return -EINVAL;
481 : : }
482 : :
483 [ + - ]: 1 : if (params->subport_profiles == NULL ||
484 [ + - ]: 1 : params->n_subport_profiles == 0 ||
485 [ + - - + ]: 1 : params->n_max_subport_profiles == 0 ||
486 : : params->n_subport_profiles > params->n_max_subport_profiles) {
487 : 0 : SCHED_LOG(ERR,
488 : : "%s: Incorrect value for subport profiles", __func__);
489 : 0 : return -EINVAL;
490 : : }
491 : :
492 [ + + ]: 2 : for (i = 0; i < params->n_subport_profiles; i++) {
493 : 1 : struct rte_sched_subport_profile_params *p =
494 : 1 : params->subport_profiles + i;
495 : : int status;
496 : :
497 : 1 : status = subport_profile_check(p, params->rate);
498 [ - + ]: 1 : if (status != 0) {
499 : 0 : SCHED_LOG(ERR,
500 : : "%s: subport profile check failed(%d)",
501 : : __func__, status);
502 : 0 : return -EINVAL;
503 : : }
504 : : }
505 : :
506 : : /* n_pipes_per_subport: non-zero, power of 2 */
507 [ + - ]: 1 : if (params->n_pipes_per_subport == 0 ||
508 : : !rte_is_power_of_2(params->n_pipes_per_subport)) {
509 : 0 : SCHED_LOG(ERR,
510 : : "%s: Incorrect value for maximum pipes number", __func__);
511 : 0 : return -EINVAL;
512 : : }
513 : :
514 : : return 0;
515 : : }
516 : :
517 : : static uint32_t
518 : 7 : rte_sched_subport_get_array_base(struct rte_sched_subport_params *params,
519 : : enum rte_sched_subport_array array)
520 : : {
521 : 7 : uint32_t n_pipes_per_subport = params->n_pipes_per_subport_enabled;
522 : 7 : uint32_t n_subport_pipe_queues =
523 : : RTE_SCHED_QUEUES_PER_PIPE * n_pipes_per_subport;
524 : :
525 : 7 : uint32_t size_pipe = n_pipes_per_subport * sizeof(struct rte_sched_pipe);
526 : 7 : uint32_t size_queue =
527 : : n_subport_pipe_queues * sizeof(struct rte_sched_queue);
528 : 7 : uint32_t size_queue_extra
529 : : = n_subport_pipe_queues * sizeof(struct rte_sched_queue_extra);
530 : 7 : uint32_t size_pipe_profiles = params->n_max_pipe_profiles *
531 : : sizeof(struct rte_sched_pipe_profile);
532 : : uint32_t size_bmp_array =
533 : 7 : rte_bitmap_get_memory_footprint(n_subport_pipe_queues);
534 : : uint32_t size_per_pipe_queue_array, size_queue_array;
535 : :
536 : : uint32_t base, i;
537 : :
538 : : size_per_pipe_queue_array = 0;
539 [ + + ]: 98 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
540 [ + + ]: 91 : if (i < RTE_SCHED_TRAFFIC_CLASS_BE)
541 : 84 : size_per_pipe_queue_array +=
542 : 84 : params->qsize[i] * sizeof(struct rte_mbuf *);
543 : : else
544 : 7 : size_per_pipe_queue_array += RTE_SCHED_MAX_QUEUES_PER_TC *
545 : 7 : params->qsize[i] * sizeof(struct rte_mbuf *);
546 : : }
547 : 7 : size_queue_array = n_pipes_per_subport * size_per_pipe_queue_array;
548 : :
549 : : base = 0;
550 : :
551 [ + + ]: 7 : if (array == e_RTE_SCHED_SUBPORT_ARRAY_PIPE)
552 : : return base;
553 : 6 : base += RTE_CACHE_LINE_ROUNDUP(size_pipe);
554 : :
555 [ + + ]: 6 : if (array == e_RTE_SCHED_SUBPORT_ARRAY_QUEUE)
556 : : return base;
557 : 5 : base += RTE_CACHE_LINE_ROUNDUP(size_queue);
558 : :
559 [ + + ]: 5 : if (array == e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA)
560 : : return base;
561 : 4 : base += RTE_CACHE_LINE_ROUNDUP(size_queue_extra);
562 : :
563 [ + + ]: 4 : if (array == e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES)
564 : : return base;
565 : 3 : base += RTE_CACHE_LINE_ROUNDUP(size_pipe_profiles);
566 : :
567 [ + + ]: 3 : if (array == e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY)
568 : : return base;
569 : 2 : base += RTE_CACHE_LINE_ROUNDUP(size_bmp_array);
570 : :
571 [ + + ]: 2 : if (array == e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY)
572 : : return base;
573 : 1 : base += RTE_CACHE_LINE_ROUNDUP(size_queue_array);
574 : :
575 : 1 : return base;
576 : : }
577 : :
578 : : static void
579 : 1 : rte_sched_subport_config_qsize(struct rte_sched_subport *subport)
580 : : {
581 : : uint32_t i;
582 : :
583 : 1 : subport->qsize_add[0] = 0;
584 : :
585 : : /* Strict priority traffic class */
586 [ + + ]: 13 : for (i = 1; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
587 : 12 : subport->qsize_add[i] = subport->qsize_add[i-1] + subport->qsize[i-1];
588 : :
589 : : /* Best-effort traffic class */
590 : 1 : subport->qsize_add[RTE_SCHED_TRAFFIC_CLASS_BE + 1] =
591 : 1 : subport->qsize_add[RTE_SCHED_TRAFFIC_CLASS_BE] +
592 : 1 : subport->qsize[RTE_SCHED_TRAFFIC_CLASS_BE];
593 : 1 : subport->qsize_add[RTE_SCHED_TRAFFIC_CLASS_BE + 2] =
594 : 1 : subport->qsize_add[RTE_SCHED_TRAFFIC_CLASS_BE + 1] +
595 : : subport->qsize[RTE_SCHED_TRAFFIC_CLASS_BE];
596 : 1 : subport->qsize_add[RTE_SCHED_TRAFFIC_CLASS_BE + 3] =
597 : 1 : subport->qsize_add[RTE_SCHED_TRAFFIC_CLASS_BE + 2] +
598 : : subport->qsize[RTE_SCHED_TRAFFIC_CLASS_BE];
599 : :
600 : 1 : subport->qsize_sum = subport->qsize_add[RTE_SCHED_TRAFFIC_CLASS_BE + 3] +
601 : : subport->qsize[RTE_SCHED_TRAFFIC_CLASS_BE];
602 : 1 : }
603 : :
604 : : static void
605 : 1 : rte_sched_port_log_pipe_profile(struct rte_sched_subport *subport, uint32_t i)
606 : : {
607 : 1 : struct rte_sched_pipe_profile *p = subport->pipe_profiles + i;
608 : :
609 : 1 : RTE_LOG(DEBUG, SCHED, "Low level config for pipe profile %u:\n"
610 : : " Token bucket: period = %"PRIu64", credits per period = %"PRIu64", size = %"PRIu64"\n"
611 : : " Traffic classes: period = %"PRIu64",\n"
612 : : " credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
613 : : ", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
614 : : ", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
615 : : " Best-effort traffic class oversubscription: weight = %hhu\n"
616 : : " WRR cost: [%hhu, %hhu, %hhu, %hhu]\n",
617 : : i,
618 : :
619 : : /* Token bucket */
620 : : p->tb_period,
621 : : p->tb_credits_per_period,
622 : : p->tb_size,
623 : :
624 : : /* Traffic classes */
625 : : p->tc_period,
626 : : p->tc_credits_per_period[0],
627 : : p->tc_credits_per_period[1],
628 : : p->tc_credits_per_period[2],
629 : : p->tc_credits_per_period[3],
630 : : p->tc_credits_per_period[4],
631 : : p->tc_credits_per_period[5],
632 : : p->tc_credits_per_period[6],
633 : : p->tc_credits_per_period[7],
634 : : p->tc_credits_per_period[8],
635 : : p->tc_credits_per_period[9],
636 : : p->tc_credits_per_period[10],
637 : : p->tc_credits_per_period[11],
638 : : p->tc_credits_per_period[12],
639 : :
640 : : /* Best-effort traffic class oversubscription */
641 : : p->tc_ov_weight,
642 : :
643 : : /* WRR */
644 : : p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p->wrr_cost[3]);
645 : 1 : }
646 : :
647 : : static void
648 : 2 : rte_sched_port_log_subport_profile(struct rte_sched_port *port, uint32_t i)
649 : : {
650 : 2 : struct rte_sched_subport_profile *p = port->subport_profiles + i;
651 : :
652 : 2 : RTE_LOG(DEBUG, SCHED, "Low level config for subport profile %u:\n"
653 : : "Token bucket: period = %"PRIu64", credits per period = %"PRIu64","
654 : : "size = %"PRIu64"\n"
655 : : "Traffic classes: period = %"PRIu64",\n"
656 : : "credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
657 : : " %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
658 : : " %"PRIu64", %"PRIu64", %"PRIu64"]\n",
659 : : i,
660 : :
661 : : /* Token bucket */
662 : : p->tb_period,
663 : : p->tb_credits_per_period,
664 : : p->tb_size,
665 : :
666 : : /* Traffic classes */
667 : : p->tc_period,
668 : : p->tc_credits_per_period[0],
669 : : p->tc_credits_per_period[1],
670 : : p->tc_credits_per_period[2],
671 : : p->tc_credits_per_period[3],
672 : : p->tc_credits_per_period[4],
673 : : p->tc_credits_per_period[5],
674 : : p->tc_credits_per_period[6],
675 : : p->tc_credits_per_period[7],
676 : : p->tc_credits_per_period[8],
677 : : p->tc_credits_per_period[9],
678 : : p->tc_credits_per_period[10],
679 : : p->tc_credits_per_period[11],
680 : : p->tc_credits_per_period[12]);
681 : 2 : }
682 : :
683 : : static inline uint64_t
684 : : rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)
685 : : {
686 : : uint64_t time = time_ms;
687 : :
688 : 29 : time = (time * rate) / 1000;
689 : :
690 : : return time;
691 : : }
692 : :
693 : : static void
694 : 1 : rte_sched_pipe_profile_convert(struct rte_sched_subport *subport,
695 : : struct rte_sched_pipe_params *src,
696 : : struct rte_sched_pipe_profile *dst,
697 : : uint64_t rate)
698 : : {
699 : : uint32_t wrr_cost[RTE_SCHED_BE_QUEUES_PER_PIPE];
700 : : uint32_t lcd1, lcd2, lcd;
701 : : uint32_t i;
702 : :
703 : : /* Token Bucket */
704 [ - + ]: 1 : if (src->tb_rate == rate) {
705 : 0 : dst->tb_credits_per_period = 1;
706 : 0 : dst->tb_period = 1;
707 : : } else {
708 : 1 : double tb_rate = (double) src->tb_rate
709 : 1 : / (double) rate;
710 : : double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
711 : :
712 : 1 : rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
713 : : &dst->tb_period);
714 : : }
715 : :
716 : 1 : dst->tb_size = src->tb_size;
717 : :
718 : : /* Traffic Classes */
719 : 1 : dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period,
720 : : rate);
721 : :
722 [ + + ]: 14 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
723 [ + - ]: 13 : if (subport->qsize[i])
724 : : dst->tc_credits_per_period[i]
725 : 13 : = rte_sched_time_ms_to_bytes(src->tc_period,
726 : : src->tc_rate[i]);
727 : :
728 : 1 : dst->tc_ov_weight = src->tc_ov_weight;
729 : :
730 : : /* WRR queues */
731 : 1 : wrr_cost[0] = src->wrr_weights[0];
732 : 1 : wrr_cost[1] = src->wrr_weights[1];
733 : 1 : wrr_cost[2] = src->wrr_weights[2];
734 [ + - ]: 1 : wrr_cost[3] = src->wrr_weights[3];
735 : :
736 : : lcd1 = rte_get_lcd(wrr_cost[0], wrr_cost[1]);
737 : : lcd2 = rte_get_lcd(wrr_cost[2], wrr_cost[3]);
738 : : lcd = rte_get_lcd(lcd1, lcd2);
739 : :
740 : 1 : wrr_cost[0] = lcd / wrr_cost[0];
741 : 1 : wrr_cost[1] = lcd / wrr_cost[1];
742 : 1 : wrr_cost[2] = lcd / wrr_cost[2];
743 : 1 : wrr_cost[3] = lcd / wrr_cost[3];
744 : :
745 : 1 : dst->wrr_cost[0] = (uint8_t) wrr_cost[0];
746 : 1 : dst->wrr_cost[1] = (uint8_t) wrr_cost[1];
747 : 1 : dst->wrr_cost[2] = (uint8_t) wrr_cost[2];
748 : 1 : dst->wrr_cost[3] = (uint8_t) wrr_cost[3];
749 : 1 : }
750 : :
751 : : static void
752 : 1 : rte_sched_subport_profile_convert(struct rte_sched_subport_profile_params *src,
753 : : struct rte_sched_subport_profile *dst,
754 : : uint64_t rate)
755 : : {
756 : : uint32_t i;
757 : :
758 : : /* Token Bucket */
759 [ + - ]: 1 : if (src->tb_rate == rate) {
760 : 1 : dst->tb_credits_per_period = 1;
761 : 1 : dst->tb_period = 1;
762 : : } else {
763 : 0 : double tb_rate = (double) src->tb_rate
764 : 0 : / (double) rate;
765 : : double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
766 : :
767 : 0 : rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
768 : : &dst->tb_period);
769 : : }
770 : :
771 : 1 : dst->tb_size = src->tb_size;
772 : :
773 : : /* Traffic Classes */
774 : 1 : dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period, rate);
775 : :
776 [ + + ]: 14 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
777 : : dst->tc_credits_per_period[i]
778 : 13 : = rte_sched_time_ms_to_bytes(src->tc_period,
779 : : src->tc_rate[i]);
780 : 1 : }
781 : :
782 : : static void
783 : 1 : rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
784 : : struct rte_sched_subport_params *params, uint64_t rate)
785 : : {
786 : : uint32_t i;
787 : :
788 [ + + ]: 2 : for (i = 0; i < subport->n_pipe_profiles; i++) {
789 : 1 : struct rte_sched_pipe_params *src = params->pipe_profiles + i;
790 : 1 : struct rte_sched_pipe_profile *dst = subport->pipe_profiles + i;
791 : :
792 : 1 : rte_sched_pipe_profile_convert(subport, src, dst, rate);
793 : 1 : rte_sched_port_log_pipe_profile(subport, i);
794 : : }
795 : :
796 : 1 : subport->pipe_tc_be_rate_max = 0;
797 [ + + ]: 2 : for (i = 0; i < subport->n_pipe_profiles; i++) {
798 : 1 : struct rte_sched_pipe_params *src = params->pipe_profiles + i;
799 : 1 : uint64_t pipe_tc_be_rate = src->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE];
800 : :
801 [ + - ]: 1 : if (subport->pipe_tc_be_rate_max < pipe_tc_be_rate)
802 : 1 : subport->pipe_tc_be_rate_max = pipe_tc_be_rate;
803 : : }
804 : 1 : }
805 : :
806 : : static void
807 : 1 : rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
808 : : struct rte_sched_port_params *params,
809 : : uint64_t rate)
810 : : {
811 : : uint32_t i;
812 : :
813 [ + + ]: 2 : for (i = 0; i < port->n_subport_profiles; i++) {
814 : 1 : struct rte_sched_subport_profile_params *src
815 : 1 : = params->subport_profiles + i;
816 : 1 : struct rte_sched_subport_profile *dst
817 : 1 : = port->subport_profiles + i;
818 : :
819 : 1 : rte_sched_subport_profile_convert(src, dst, rate);
820 : 1 : rte_sched_port_log_subport_profile(port, i);
821 : : }
822 : 1 : }
823 : :
824 : : static int
825 : 1 : rte_sched_subport_check_params(struct rte_sched_subport_params *params,
826 : : uint32_t n_max_pipes_per_subport,
827 : : uint64_t rate)
828 : : {
829 : : uint32_t i;
830 : :
831 : : /* Check user parameters */
832 [ - + ]: 1 : if (params == NULL) {
833 : 0 : SCHED_LOG(ERR,
834 : : "%s: Incorrect value for parameter params", __func__);
835 : 0 : return -EINVAL;
836 : : }
837 : :
838 : : /* qsize: if non-zero, power of 2,
839 : : * no bigger than 32K (due to 16-bit read/write pointers)
840 : : */
841 [ + + ]: 14 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
842 : 13 : uint16_t qsize = params->qsize[i];
843 : :
844 [ + - - + ]: 13 : if (qsize != 0 && !rte_is_power_of_2(qsize)) {
845 : 0 : SCHED_LOG(ERR,
846 : : "%s: Incorrect value for qsize", __func__);
847 : 0 : return -EINVAL;
848 : : }
849 : : }
850 : :
851 [ - + ]: 1 : if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
852 : 0 : SCHED_LOG(ERR, "%s: Incorrect qsize", __func__);
853 : 0 : return -EINVAL;
854 : : }
855 : :
856 : : /* n_pipes_per_subport: non-zero, power of 2 */
857 [ + - + - ]: 1 : if (params->n_pipes_per_subport_enabled == 0 ||
858 : : params->n_pipes_per_subport_enabled > n_max_pipes_per_subport ||
859 : : !rte_is_power_of_2(params->n_pipes_per_subport_enabled)) {
860 : 0 : SCHED_LOG(ERR,
861 : : "%s: Incorrect value for pipes number", __func__);
862 : 0 : return -EINVAL;
863 : : }
864 : :
865 : : /* pipe_profiles and n_pipe_profiles */
866 [ + - ]: 1 : if (params->pipe_profiles == NULL ||
867 [ + - ]: 1 : params->n_pipe_profiles == 0 ||
868 [ + - - + ]: 1 : params->n_max_pipe_profiles == 0 ||
869 : : params->n_pipe_profiles > params->n_max_pipe_profiles) {
870 : 0 : SCHED_LOG(ERR,
871 : : "%s: Incorrect value for pipe profiles", __func__);
872 : 0 : return -EINVAL;
873 : : }
874 : :
875 [ + + ]: 2 : for (i = 0; i < params->n_pipe_profiles; i++) {
876 : 1 : struct rte_sched_pipe_params *p = params->pipe_profiles + i;
877 : : int status;
878 : :
879 : 1 : status = pipe_profile_check(p, rate, ¶ms->qsize[0]);
880 [ - + ]: 1 : if (status != 0) {
881 : 0 : SCHED_LOG(ERR,
882 : : "%s: Pipe profile check failed(%d)", __func__, status);
883 : 0 : return -EINVAL;
884 : : }
885 : : }
886 : :
887 : : return 0;
888 : : }
889 : :
890 : : uint32_t
891 : 0 : rte_sched_port_get_memory_footprint(struct rte_sched_port_params *port_params,
892 : : struct rte_sched_subport_params **subport_params)
893 : : {
894 : : uint32_t size0 = 0, size1 = 0, i;
895 : : int status;
896 : :
897 : 0 : status = rte_sched_port_check_params(port_params);
898 [ # # ]: 0 : if (status != 0) {
899 : 0 : SCHED_LOG(ERR,
900 : : "%s: Port scheduler port params check failed (%d)",
901 : : __func__, status);
902 : :
903 : 0 : return 0;
904 : : }
905 : :
906 [ # # ]: 0 : for (i = 0; i < port_params->n_subports_per_port; i++) {
907 : 0 : struct rte_sched_subport_params *sp = subport_params[i];
908 : :
909 : 0 : status = rte_sched_subport_check_params(sp,
910 : : port_params->n_pipes_per_subport,
911 : : port_params->rate);
912 [ # # ]: 0 : if (status != 0) {
913 : 0 : SCHED_LOG(ERR,
914 : : "%s: Port scheduler subport params check failed (%d)",
915 : : __func__, status);
916 : :
917 : 0 : return 0;
918 : : }
919 : : }
920 : :
921 : : size0 = sizeof(struct rte_sched_port);
922 : :
923 [ # # ]: 0 : for (i = 0; i < port_params->n_subports_per_port; i++) {
924 : 0 : struct rte_sched_subport_params *sp = subport_params[i];
925 : :
926 : 0 : size1 += rte_sched_subport_get_array_base(sp,
927 : : e_RTE_SCHED_SUBPORT_ARRAY_TOTAL);
928 : : }
929 : :
930 : 0 : return size0 + size1;
931 : : }
932 : :
933 : : struct rte_sched_port *
934 : 1 : rte_sched_port_config(struct rte_sched_port_params *params)
935 : : {
936 : : struct rte_sched_port *port = NULL;
937 : : uint32_t size0, size1, size2;
938 : : uint32_t cycles_per_byte;
939 : : uint32_t i, j;
940 : : int status;
941 : :
942 : 1 : status = rte_sched_port_check_params(params);
943 [ - + ]: 1 : if (status != 0) {
944 : 0 : SCHED_LOG(ERR,
945 : : "%s: Port scheduler params check failed (%d)",
946 : : __func__, status);
947 : 0 : return NULL;
948 : : }
949 : :
950 : : size0 = sizeof(struct rte_sched_port);
951 : 1 : size1 = params->n_subports_per_port * sizeof(struct rte_sched_subport *);
952 : 1 : size2 = params->n_max_subport_profiles *
953 : : sizeof(struct rte_sched_subport_profile);
954 : :
955 : : /* Allocate memory to store the data structures */
956 : 1 : port = rte_zmalloc_socket("qos_params", size0 + size1,
957 : : RTE_CACHE_LINE_SIZE, params->socket);
958 [ - + ]: 1 : if (port == NULL) {
959 : 0 : SCHED_LOG(ERR, "%s: Memory allocation fails", __func__);
960 : :
961 : 0 : return NULL;
962 : : }
963 : :
964 : : /* Allocate memory to store the subport profile */
965 : 1 : port->subport_profiles = rte_zmalloc_socket("subport_profile", size2,
966 : : RTE_CACHE_LINE_SIZE, params->socket);
967 [ - + ]: 1 : if (port->subport_profiles == NULL) {
968 : 0 : SCHED_LOG(ERR, "%s: Memory allocation fails", __func__);
969 : 0 : rte_free(port);
970 : 0 : return NULL;
971 : : }
972 : :
973 : : /* User parameters */
974 : 1 : port->n_subports_per_port = params->n_subports_per_port;
975 : 1 : port->n_subport_profiles = params->n_subport_profiles;
976 : 1 : port->n_max_subport_profiles = params->n_max_subport_profiles;
977 : 1 : port->n_pipes_per_subport = params->n_pipes_per_subport;
978 : 1 : port->n_pipes_per_subport_log2 =
979 : : rte_ctz32(params->n_pipes_per_subport);
980 : 1 : port->socket = params->socket;
981 : :
982 [ + + ]: 14 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
983 : 13 : port->pipe_queue[i] = i;
984 : :
985 [ + + ]: 17 : for (i = 0, j = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++) {
986 : 16 : port->pipe_tc[i] = j;
987 : :
988 [ + + ]: 16 : if (j < RTE_SCHED_TRAFFIC_CLASS_BE)
989 : 12 : j++;
990 : : }
991 : :
992 [ + + ]: 17 : for (i = 0, j = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++) {
993 : 16 : port->tc_queue[i] = j;
994 : :
995 [ + + ]: 16 : if (i >= RTE_SCHED_TRAFFIC_CLASS_BE)
996 : 4 : j++;
997 : : }
998 : 1 : port->rate = params->rate;
999 : 1 : port->mtu = params->mtu + params->frame_overhead;
1000 : 1 : port->frame_overhead = params->frame_overhead;
1001 : :
1002 : : /* Timing */
1003 : 1 : port->time_cpu_cycles = rte_get_tsc_cycles();
1004 : 1 : port->time_cpu_bytes = 0;
1005 : 1 : port->time = 0;
1006 : :
1007 : : /* Subport profile table */
1008 : 1 : rte_sched_port_config_subport_profile_table(port, params, port->rate);
1009 : :
1010 : 1 : cycles_per_byte = (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
1011 : 1 : / params->rate;
1012 : 1 : port->inv_cycles_per_byte = rte_reciprocal_value(cycles_per_byte);
1013 : 1 : port->cycles_per_byte = cycles_per_byte;
1014 : :
1015 : : /* Grinders */
1016 : 1 : port->pkts_out = NULL;
1017 : 1 : port->n_pkts_out = 0;
1018 : 1 : port->subport_id = 0;
1019 : :
1020 : 1 : return port;
1021 : : }
1022 : :
1023 : : static inline void
1024 : 1 : rte_sched_subport_free(struct rte_sched_port *port,
1025 : : struct rte_sched_subport *subport)
1026 : : {
1027 : : uint32_t n_subport_pipe_queues;
1028 : : uint32_t qindex;
1029 : :
1030 [ + - ]: 1 : if (subport == NULL)
1031 : : return;
1032 : :
1033 : : n_subport_pipe_queues = rte_sched_subport_pipe_queues(subport);
1034 : :
1035 : : /* Free enqueued mbufs */
1036 [ + + ]: 16385 : for (qindex = 0; qindex < n_subport_pipe_queues; qindex++) {
1037 : : struct rte_mbuf **mbufs =
1038 : : rte_sched_subport_pipe_qbase(subport, qindex);
1039 : : uint16_t qsize = rte_sched_subport_pipe_qsize(port, subport, qindex);
1040 [ + - ]: 16384 : if (qsize != 0) {
1041 : 16384 : struct rte_sched_queue *queue = subport->queue + qindex;
1042 : 16384 : uint16_t qr = queue->qr & (qsize - 1);
1043 : 16384 : uint16_t qw = queue->qw & (qsize - 1);
1044 : :
1045 [ - + ]: 16384 : for (; qr != qw; qr = (qr + 1) & (qsize - 1))
1046 : 0 : rte_pktmbuf_free(mbufs[qr]);
1047 : : }
1048 : : }
1049 : :
1050 : 1 : rte_free(subport);
1051 : : }
1052 : :
1053 : : void
1054 : 1 : rte_sched_port_free(struct rte_sched_port *port)
1055 : : {
1056 : : uint32_t i;
1057 : :
1058 : : /* Check user parameters */
1059 [ + - ]: 1 : if (port == NULL)
1060 : : return;
1061 : :
1062 [ + + ]: 2 : for (i = 0; i < port->n_subports_per_port; i++)
1063 : 1 : rte_sched_subport_free(port, port->subports[i]);
1064 : :
1065 : 1 : rte_free(port->subport_profiles);
1066 : 1 : rte_free(port);
1067 : : }
1068 : :
1069 : : static void
1070 : 0 : rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
1071 : : {
1072 : : uint32_t i;
1073 : :
1074 [ # # ]: 0 : for (i = 0; i < n_subports; i++) {
1075 : 0 : struct rte_sched_subport *subport = port->subports[i];
1076 : :
1077 : 0 : rte_sched_subport_free(port, subport);
1078 : : }
1079 : :
1080 : 0 : rte_free(port->subport_profiles);
1081 : 0 : rte_free(port);
1082 : 0 : }
1083 : :
1084 : : static int
1085 : 0 : rte_sched_red_config(struct rte_sched_port *port,
1086 : : struct rte_sched_subport *s,
1087 : : struct rte_sched_subport_params *params,
1088 : : uint32_t n_subports)
1089 : : {
1090 : : uint32_t i;
1091 : :
1092 [ # # ]: 0 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
1093 : :
1094 : : uint32_t j;
1095 : :
1096 [ # # ]: 0 : for (j = 0; j < RTE_COLORS; j++) {
1097 : : /* if min/max are both zero, then RED is disabled */
1098 : 0 : if ((params->cman_params->red_params[i][j].min_th |
1099 [ # # ]: 0 : params->cman_params->red_params[i][j].max_th) == 0) {
1100 : 0 : continue;
1101 : : }
1102 : :
1103 [ # # ]: 0 : if (rte_red_config_init(&s->red_config[i][j],
1104 : 0 : params->cman_params->red_params[i][j].wq_log2,
1105 : : params->cman_params->red_params[i][j].min_th,
1106 : : params->cman_params->red_params[i][j].max_th,
1107 : 0 : params->cman_params->red_params[i][j].maxp_inv) != 0) {
1108 : 0 : rte_sched_free_memory(port, n_subports);
1109 : :
1110 : 0 : SCHED_LOG(NOTICE,
1111 : : "%s: RED configuration init fails", __func__);
1112 : 0 : return -EINVAL;
1113 : : }
1114 : : }
1115 : : }
1116 : 0 : s->cman = RTE_SCHED_CMAN_RED;
1117 : 0 : return 0;
1118 : : }
1119 : :
1120 : : static int
1121 : 0 : rte_sched_pie_config(struct rte_sched_port *port,
1122 : : struct rte_sched_subport *s,
1123 : : struct rte_sched_subport_params *params,
1124 : : uint32_t n_subports)
1125 : : {
1126 : : uint32_t i;
1127 : :
1128 [ # # ]: 0 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
1129 [ # # ]: 0 : if (params->cman_params->pie_params[i].tailq_th > params->qsize[i]) {
1130 : 0 : SCHED_LOG(NOTICE,
1131 : : "%s: PIE tailq threshold incorrect", __func__);
1132 : 0 : return -EINVAL;
1133 : : }
1134 : :
1135 [ # # ]: 0 : if (rte_pie_config_init(&s->pie_config[i],
1136 : 0 : params->cman_params->pie_params[i].qdelay_ref,
1137 : 0 : params->cman_params->pie_params[i].dp_update_interval,
1138 : 0 : params->cman_params->pie_params[i].max_burst,
1139 : : params->cman_params->pie_params[i].tailq_th) != 0) {
1140 : 0 : rte_sched_free_memory(port, n_subports);
1141 : :
1142 : 0 : SCHED_LOG(NOTICE,
1143 : : "%s: PIE configuration init fails", __func__);
1144 : 0 : return -EINVAL;
1145 : : }
1146 : : }
1147 : 0 : s->cman = RTE_SCHED_CMAN_PIE;
1148 : 0 : return 0;
1149 : : }
1150 : :
1151 : : static int
1152 : 0 : rte_sched_cman_config(struct rte_sched_port *port,
1153 : : struct rte_sched_subport *s,
1154 : : struct rte_sched_subport_params *params,
1155 : : uint32_t n_subports)
1156 : : {
1157 [ # # ]: 0 : if (params->cman_params->cman_mode == RTE_SCHED_CMAN_RED)
1158 : 0 : return rte_sched_red_config(port, s, params, n_subports);
1159 : :
1160 [ # # ]: 0 : else if (params->cman_params->cman_mode == RTE_SCHED_CMAN_PIE)
1161 : 0 : return rte_sched_pie_config(port, s, params, n_subports);
1162 : :
1163 : : return -EINVAL;
1164 : : }
1165 : :
1166 : : int
1167 : 0 : rte_sched_subport_tc_ov_config(struct rte_sched_port *port,
1168 : : uint32_t subport_id,
1169 : : bool tc_ov_enable)
1170 : : {
1171 : : struct rte_sched_subport *s;
1172 : :
1173 [ # # ]: 0 : if (port == NULL) {
1174 : 0 : SCHED_LOG(ERR,
1175 : : "%s: Incorrect value for parameter port", __func__);
1176 : 0 : return -EINVAL;
1177 : : }
1178 : :
1179 [ # # ]: 0 : if (subport_id >= port->n_subports_per_port) {
1180 : 0 : SCHED_LOG(ERR,
1181 : : "%s: Incorrect value for parameter subport id", __func__);
1182 : 0 : return -EINVAL;
1183 : : }
1184 : :
1185 : 0 : s = port->subports[subport_id];
1186 : 0 : s->tc_ov_enabled = tc_ov_enable ? 1 : 0;
1187 : :
1188 : 0 : return 0;
1189 : : }
1190 : :
1191 : : int
1192 : 1 : rte_sched_subport_config(struct rte_sched_port *port,
1193 : : uint32_t subport_id,
1194 : : struct rte_sched_subport_params *params,
1195 : : uint32_t subport_profile_id)
1196 : : {
1197 : : struct rte_sched_subport *s = NULL;
1198 : : uint32_t n_subports = subport_id;
1199 : : struct rte_sched_subport_profile *profile;
1200 : : uint32_t n_subport_pipe_queues, i;
1201 : : uint32_t size0, size1, bmp_mem_size;
1202 : : int status;
1203 : : int ret;
1204 : :
1205 : : /* Check user parameters */
1206 [ - + ]: 1 : if (port == NULL) {
1207 : 0 : SCHED_LOG(ERR,
1208 : : "%s: Incorrect value for parameter port", __func__);
1209 : 0 : return 0;
1210 : : }
1211 : :
1212 [ - + ]: 1 : if (subport_id >= port->n_subports_per_port) {
1213 : 0 : SCHED_LOG(ERR,
1214 : : "%s: Incorrect value for subport id", __func__);
1215 : : ret = -EINVAL;
1216 : 0 : goto out;
1217 : : }
1218 : :
1219 [ - + ]: 1 : if (subport_profile_id >= port->n_max_subport_profiles) {
1220 : 0 : SCHED_LOG(ERR, "%s: "
1221 : : "Number of subport profile exceeds the max limit",
1222 : : __func__);
1223 : : ret = -EINVAL;
1224 : 0 : goto out;
1225 : : }
1226 : :
1227 : : /** Memory is allocated only on first invocation of the api for a
1228 : : * given subport. Subsequent invocation on same subport will just
1229 : : * update subport bandwidth parameter.
1230 : : */
1231 [ + - ]: 1 : if (port->subports[subport_id] == NULL) {
1232 : :
1233 : 1 : status = rte_sched_subport_check_params(params,
1234 : : port->n_pipes_per_subport,
1235 : : port->rate);
1236 [ - + ]: 1 : if (status != 0) {
1237 : 0 : SCHED_LOG(NOTICE,
1238 : : "%s: Port scheduler params check failed (%d)",
1239 : : __func__, status);
1240 : : ret = -EINVAL;
1241 : 0 : goto out;
1242 : : }
1243 : :
1244 : : /* Determine the amount of memory to allocate */
1245 : : size0 = sizeof(struct rte_sched_subport);
1246 : 1 : size1 = rte_sched_subport_get_array_base(params,
1247 : : e_RTE_SCHED_SUBPORT_ARRAY_TOTAL);
1248 : :
1249 : : /* Allocate memory to store the data structures */
1250 : 1 : s = rte_zmalloc_socket("subport_params", size0 + size1,
1251 : : RTE_CACHE_LINE_SIZE, port->socket);
1252 [ - + ]: 1 : if (s == NULL) {
1253 : 0 : SCHED_LOG(ERR,
1254 : : "%s: Memory allocation fails", __func__);
1255 : : ret = -ENOMEM;
1256 : 0 : goto out;
1257 : : }
1258 : :
1259 : 1 : n_subports++;
1260 : :
1261 : : /* Port */
1262 : 1 : port->subports[subport_id] = s;
1263 : :
1264 : 1 : s->tb_time = port->time;
1265 : :
1266 : : /* compile time checks */
1267 : : RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
1268 : : RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS &
1269 : : (RTE_SCHED_PORT_N_GRINDERS - 1));
1270 : :
1271 : : /* User parameters */
1272 : 1 : s->n_pipes_per_subport_enabled =
1273 : 1 : params->n_pipes_per_subport_enabled;
1274 [ - + ]: 1 : memcpy(s->qsize, params->qsize, sizeof(params->qsize));
1275 : 1 : s->n_pipe_profiles = params->n_pipe_profiles;
1276 : 1 : s->n_max_pipe_profiles = params->n_max_pipe_profiles;
1277 : :
1278 : : /* TC oversubscription is enabled by default */
1279 : 1 : s->tc_ov_enabled = 1;
1280 : :
1281 [ - + ]: 1 : if (params->cman_params != NULL) {
1282 : 0 : s->cman_enabled = true;
1283 : 0 : status = rte_sched_cman_config(port, s, params, n_subports);
1284 [ # # ]: 0 : if (status) {
1285 : 0 : SCHED_LOG(NOTICE,
1286 : : "%s: CMAN configuration fails", __func__);
1287 : 0 : return status;
1288 : : }
1289 : : } else {
1290 : 1 : s->cman_enabled = false;
1291 : : }
1292 : :
1293 : : /* Scheduling loop detection */
1294 : 1 : s->pipe_loop = RTE_SCHED_PIPE_INVALID;
1295 : 1 : s->pipe_exhaustion = 0;
1296 : :
1297 : : /* Grinders */
1298 : 1 : s->busy_grinders = 0;
1299 : :
1300 : : /* Queue base calculation */
1301 : 1 : rte_sched_subport_config_qsize(s);
1302 : :
1303 : : /* Large data structures */
1304 : 1 : s->pipe = (struct rte_sched_pipe *)
1305 : 1 : (s->memory + rte_sched_subport_get_array_base(params,
1306 : : e_RTE_SCHED_SUBPORT_ARRAY_PIPE));
1307 : 1 : s->queue = (struct rte_sched_queue *)
1308 : 1 : (s->memory + rte_sched_subport_get_array_base(params,
1309 : : e_RTE_SCHED_SUBPORT_ARRAY_QUEUE));
1310 : 1 : s->queue_extra = (struct rte_sched_queue_extra *)
1311 : 1 : (s->memory + rte_sched_subport_get_array_base(params,
1312 : : e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA));
1313 : 1 : s->pipe_profiles = (struct rte_sched_pipe_profile *)
1314 : 1 : (s->memory + rte_sched_subport_get_array_base(params,
1315 : : e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES));
1316 : 1 : s->bmp_array = s->memory + rte_sched_subport_get_array_base(
1317 : : params, e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY);
1318 : 1 : s->queue_array = (struct rte_mbuf **)
1319 : 1 : (s->memory + rte_sched_subport_get_array_base(params,
1320 : : e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY));
1321 : :
1322 : : /* Pipe profile table */
1323 : 1 : rte_sched_subport_config_pipe_profile_table(s, params,
1324 : : port->rate);
1325 : :
1326 : : /* Bitmap */
1327 : : n_subport_pipe_queues = rte_sched_subport_pipe_queues(s);
1328 : 1 : bmp_mem_size = rte_bitmap_get_memory_footprint(
1329 : : n_subport_pipe_queues);
1330 : 1 : s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
1331 : : bmp_mem_size);
1332 [ - + ]: 1 : if (s->bmp == NULL) {
1333 : 0 : SCHED_LOG(ERR,
1334 : : "%s: Subport bitmap init error", __func__);
1335 : : ret = -EINVAL;
1336 : 0 : goto out;
1337 : : }
1338 : :
1339 [ + + ]: 9 : for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++)
1340 : 8 : s->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
1341 : :
1342 : : /* TC oversubscription */
1343 : 1 : s->tc_ov_wm_min = port->mtu;
1344 : 1 : s->tc_ov_period_id = 0;
1345 : 1 : s->tc_ov = 0;
1346 : 1 : s->tc_ov_n = 0;
1347 : 1 : s->tc_ov_rate = 0;
1348 : : }
1349 : :
1350 : : {
1351 : : /* update subport parameters from subport profile table*/
1352 : 1 : profile = port->subport_profiles + subport_profile_id;
1353 : :
1354 : 1 : s = port->subports[subport_id];
1355 : :
1356 : 1 : s->tb_credits = profile->tb_size / 2;
1357 : :
1358 : 1 : s->tc_time = port->time + profile->tc_period;
1359 : :
1360 [ + + ]: 14 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
1361 [ + - ]: 13 : if (s->qsize[i])
1362 : 13 : s->tc_credits[i] =
1363 : 13 : profile->tc_credits_per_period[i];
1364 : : else
1365 : 0 : profile->tc_credits_per_period[i] = 0;
1366 : :
1367 : 1 : s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(profile->tc_period,
1368 : : s->pipe_tc_be_rate_max);
1369 : 1 : s->tc_ov_wm = s->tc_ov_wm_max;
1370 : 1 : s->profile = subport_profile_id;
1371 : :
1372 : : }
1373 : :
1374 : 1 : rte_sched_port_log_subport_profile(port, subport_profile_id);
1375 : :
1376 : 1 : return 0;
1377 : :
1378 : 0 : out:
1379 : 0 : rte_sched_free_memory(port, n_subports);
1380 : :
1381 : 0 : return ret;
1382 : : }
1383 : :
1384 : : int
1385 : 1024 : rte_sched_pipe_config(struct rte_sched_port *port,
1386 : : uint32_t subport_id,
1387 : : uint32_t pipe_id,
1388 : : int32_t pipe_profile)
1389 : : {
1390 : : struct rte_sched_subport *s;
1391 : : struct rte_sched_subport_profile *sp;
1392 : : struct rte_sched_pipe *p;
1393 : : struct rte_sched_pipe_profile *params;
1394 : 1024 : uint32_t n_subports = subport_id + 1;
1395 : : uint32_t deactivate, profile, i;
1396 : : int ret;
1397 : :
1398 : : /* Check user parameters */
1399 : 1024 : profile = (uint32_t) pipe_profile;
1400 : : deactivate = (pipe_profile < 0);
1401 : :
1402 [ - + ]: 1024 : if (port == NULL) {
1403 : 0 : SCHED_LOG(ERR,
1404 : : "%s: Incorrect value for parameter port", __func__);
1405 : 0 : return -EINVAL;
1406 : : }
1407 : :
1408 [ - + ]: 1024 : if (subport_id >= port->n_subports_per_port) {
1409 : 0 : SCHED_LOG(ERR,
1410 : : "%s: Incorrect value for parameter subport id", __func__);
1411 : : ret = -EINVAL;
1412 : 0 : goto out;
1413 : : }
1414 : :
1415 : 1024 : s = port->subports[subport_id];
1416 [ - + ]: 1024 : if (pipe_id >= s->n_pipes_per_subport_enabled) {
1417 : 0 : SCHED_LOG(ERR,
1418 : : "%s: Incorrect value for parameter pipe id", __func__);
1419 : : ret = -EINVAL;
1420 : 0 : goto out;
1421 : : }
1422 : :
1423 [ + - - + ]: 1024 : if (!deactivate && profile >= s->n_pipe_profiles) {
1424 : 0 : SCHED_LOG(ERR,
1425 : : "%s: Incorrect value for parameter pipe profile", __func__);
1426 : : ret = -EINVAL;
1427 : 0 : goto out;
1428 : : }
1429 : :
1430 : 1024 : sp = port->subport_profiles + s->profile;
1431 : : /* Handle the case when pipe already has a valid configuration */
1432 : 1024 : p = s->pipe + pipe_id;
1433 [ - + ]: 1024 : if (p->tb_time) {
1434 : 0 : params = s->pipe_profiles + p->profile;
1435 : :
1436 : 0 : double subport_tc_be_rate =
1437 : 0 : (double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
1438 : 0 : / (double) sp->tc_period;
1439 : 0 : double pipe_tc_be_rate =
1440 : 0 : (double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
1441 : 0 : / (double) params->tc_period;
1442 : 0 : uint32_t tc_be_ov = s->tc_ov;
1443 : :
1444 : : /* Unplug pipe from its subport */
1445 : 0 : s->tc_ov_n -= params->tc_ov_weight;
1446 : 0 : s->tc_ov_rate -= pipe_tc_be_rate;
1447 : 0 : s->tc_ov = s->tc_ov_rate > subport_tc_be_rate;
1448 : :
1449 [ # # ]: 0 : if (s->tc_ov != tc_be_ov) {
1450 : 0 : SCHED_LOG(DEBUG,
1451 : : "Subport %u Best-effort TC oversubscription is OFF (%.4lf >= %.4lf)",
1452 : : subport_id, subport_tc_be_rate, s->tc_ov_rate);
1453 : : }
1454 : :
1455 : : /* Reset the pipe */
1456 : : memset(p, 0, sizeof(struct rte_sched_pipe));
1457 : : }
1458 : :
1459 [ + - ]: 1024 : if (deactivate)
1460 : : return 0;
1461 : :
1462 : : /* Apply the new pipe configuration */
1463 : 1024 : p->profile = profile;
1464 : 1024 : params = s->pipe_profiles + p->profile;
1465 : :
1466 : : /* Token Bucket (TB) */
1467 : 1024 : p->tb_time = port->time;
1468 : 1024 : p->tb_credits = params->tb_size / 2;
1469 : :
1470 : : /* Traffic Classes (TCs) */
1471 : 1024 : p->tc_time = port->time + params->tc_period;
1472 : :
1473 [ + + ]: 14336 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
1474 [ + - ]: 13312 : if (s->qsize[i])
1475 : 13312 : p->tc_credits[i] = params->tc_credits_per_period[i];
1476 : :
1477 : : {
1478 : : /* Subport best effort tc oversubscription */
1479 : 1024 : double subport_tc_be_rate =
1480 : 1024 : (double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
1481 : 1024 : / (double) sp->tc_period;
1482 : 1024 : double pipe_tc_be_rate =
1483 : 1024 : (double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
1484 : 1024 : / (double) params->tc_period;
1485 : 1024 : uint32_t tc_be_ov = s->tc_ov;
1486 : :
1487 : 1024 : s->tc_ov_n += params->tc_ov_weight;
1488 : 1024 : s->tc_ov_rate += pipe_tc_be_rate;
1489 : 1024 : s->tc_ov = s->tc_ov_rate > subport_tc_be_rate;
1490 : :
1491 [ - + ]: 1024 : if (s->tc_ov != tc_be_ov) {
1492 : 0 : SCHED_LOG(DEBUG,
1493 : : "Subport %u Best effort TC oversubscription is ON (%.4lf < %.4lf)",
1494 : : subport_id, subport_tc_be_rate, s->tc_ov_rate);
1495 : : }
1496 : 1024 : p->tc_ov_period_id = s->tc_ov_period_id;
1497 : 1024 : p->tc_ov_credits = s->tc_ov_wm;
1498 : : }
1499 : :
1500 : 1024 : return 0;
1501 : :
1502 : 0 : out:
1503 : 0 : rte_sched_free_memory(port, n_subports);
1504 : :
1505 : 0 : return ret;
1506 : : }
1507 : :
1508 : : int
1509 : 0 : rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
1510 : : uint32_t subport_id,
1511 : : struct rte_sched_pipe_params *params,
1512 : : uint32_t *pipe_profile_id)
1513 : : {
1514 : : struct rte_sched_subport *s;
1515 : : struct rte_sched_pipe_profile *pp;
1516 : : uint32_t i;
1517 : : int status;
1518 : :
1519 : : /* Port */
1520 [ # # ]: 0 : if (port == NULL) {
1521 : 0 : SCHED_LOG(ERR,
1522 : : "%s: Incorrect value for parameter port", __func__);
1523 : 0 : return -EINVAL;
1524 : : }
1525 : :
1526 : : /* Subport id not exceeds the max limit */
1527 [ # # ]: 0 : if (subport_id > port->n_subports_per_port) {
1528 : 0 : SCHED_LOG(ERR,
1529 : : "%s: Incorrect value for subport id", __func__);
1530 : 0 : return -EINVAL;
1531 : : }
1532 : :
1533 : 0 : s = port->subports[subport_id];
1534 : :
1535 : : /* Pipe profiles exceeds the max limit */
1536 [ # # ]: 0 : if (s->n_pipe_profiles >= s->n_max_pipe_profiles) {
1537 : 0 : SCHED_LOG(ERR,
1538 : : "%s: Number of pipe profiles exceeds the max limit", __func__);
1539 : 0 : return -EINVAL;
1540 : : }
1541 : :
1542 : : /* Pipe params */
1543 : 0 : status = pipe_profile_check(params, port->rate, &s->qsize[0]);
1544 [ # # ]: 0 : if (status != 0) {
1545 : 0 : SCHED_LOG(ERR,
1546 : : "%s: Pipe profile check failed(%d)", __func__, status);
1547 : 0 : return -EINVAL;
1548 : : }
1549 : :
1550 : 0 : pp = &s->pipe_profiles[s->n_pipe_profiles];
1551 : 0 : rte_sched_pipe_profile_convert(s, params, pp, port->rate);
1552 : :
1553 : : /* Pipe profile should not exists */
1554 [ # # ]: 0 : for (i = 0; i < s->n_pipe_profiles; i++)
1555 [ # # ]: 0 : if (memcmp(s->pipe_profiles + i, pp, sizeof(*pp)) == 0) {
1556 : 0 : SCHED_LOG(ERR,
1557 : : "%s: Pipe profile exists", __func__);
1558 : 0 : return -EINVAL;
1559 : : }
1560 : :
1561 : : /* Pipe profile commit */
1562 : 0 : *pipe_profile_id = s->n_pipe_profiles;
1563 : 0 : s->n_pipe_profiles++;
1564 : :
1565 [ # # ]: 0 : if (s->pipe_tc_be_rate_max < params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE])
1566 : 0 : s->pipe_tc_be_rate_max = params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE];
1567 : :
1568 : 0 : rte_sched_port_log_pipe_profile(s, *pipe_profile_id);
1569 : :
1570 : 0 : return 0;
1571 : : }
1572 : :
1573 : : int
1574 : 0 : rte_sched_port_subport_profile_add(struct rte_sched_port *port,
1575 : : struct rte_sched_subport_profile_params *params,
1576 : : uint32_t *subport_profile_id)
1577 : : {
1578 : : int status;
1579 : : uint32_t i;
1580 : : struct rte_sched_subport_profile *dst;
1581 : :
1582 : : /* Port */
1583 [ # # ]: 0 : if (port == NULL) {
1584 : 0 : SCHED_LOG(ERR, "%s: "
1585 : : "Incorrect value for parameter port", __func__);
1586 : 0 : return -EINVAL;
1587 : : }
1588 : :
1589 [ # # ]: 0 : if (params == NULL) {
1590 : 0 : SCHED_LOG(ERR, "%s: "
1591 : : "Incorrect value for parameter profile", __func__);
1592 : 0 : return -EINVAL;
1593 : : }
1594 : :
1595 [ # # ]: 0 : if (subport_profile_id == NULL) {
1596 : 0 : SCHED_LOG(ERR, "%s: "
1597 : : "Incorrect value for parameter subport_profile_id",
1598 : : __func__);
1599 : 0 : return -EINVAL;
1600 : : }
1601 : :
1602 : 0 : dst = port->subport_profiles + port->n_subport_profiles;
1603 : :
1604 : : /* Subport profiles exceeds the max limit */
1605 [ # # ]: 0 : if (port->n_subport_profiles >= port->n_max_subport_profiles) {
1606 : 0 : SCHED_LOG(ERR, "%s: "
1607 : : "Number of subport profiles exceeds the max limit",
1608 : : __func__);
1609 : 0 : return -EINVAL;
1610 : : }
1611 : :
1612 : 0 : status = subport_profile_check(params, port->rate);
1613 [ # # ]: 0 : if (status != 0) {
1614 : 0 : SCHED_LOG(ERR,
1615 : : "%s: subport profile check failed(%d)", __func__, status);
1616 : 0 : return -EINVAL;
1617 : : }
1618 : :
1619 : 0 : rte_sched_subport_profile_convert(params, dst, port->rate);
1620 : :
1621 : : /* Subport profile should not exists */
1622 [ # # ]: 0 : for (i = 0; i < port->n_subport_profiles; i++)
1623 [ # # ]: 0 : if (memcmp(port->subport_profiles + i,
1624 : : dst, sizeof(*dst)) == 0) {
1625 : 0 : SCHED_LOG(ERR,
1626 : : "%s: subport profile exists", __func__);
1627 : 0 : return -EINVAL;
1628 : : }
1629 : :
1630 : : /* Subport profile commit */
1631 : 0 : *subport_profile_id = port->n_subport_profiles;
1632 : 0 : port->n_subport_profiles++;
1633 : :
1634 : 0 : rte_sched_port_log_subport_profile(port, *subport_profile_id);
1635 : :
1636 : 0 : return 0;
1637 : : }
1638 : :
1639 : : static inline uint32_t
1640 : : rte_sched_port_qindex(struct rte_sched_port *port,
1641 : : uint32_t subport,
1642 : : uint32_t pipe,
1643 : : uint32_t traffic_class,
1644 : : uint32_t queue)
1645 : : {
1646 : 10 : return ((subport & (port->n_subports_per_port - 1)) <<
1647 : 10 : (port->n_pipes_per_subport_log2 + 4)) |
1648 : 10 : ((pipe &
1649 : 10 : (port->subports[subport]->n_pipes_per_subport_enabled - 1)) << 4) |
1650 : 10 : ((rte_sched_port_pipe_queue(port, traffic_class) + queue) &
1651 : : (RTE_SCHED_QUEUES_PER_PIPE - 1));
1652 : : }
1653 : :
1654 : : void
1655 : 10 : rte_sched_port_pkt_write(struct rte_sched_port *port,
1656 : : struct rte_mbuf *pkt,
1657 : : uint32_t subport, uint32_t pipe,
1658 : : uint32_t traffic_class,
1659 : : uint32_t queue, enum rte_color color)
1660 : : {
1661 : : uint32_t queue_id =
1662 : : rte_sched_port_qindex(port, subport, pipe, traffic_class, queue);
1663 : :
1664 : 10 : rte_mbuf_sched_set(pkt, queue_id, traffic_class, (uint8_t)color);
1665 : 10 : }
1666 : :
1667 : : void
1668 : 10 : rte_sched_port_pkt_read_tree_path(struct rte_sched_port *port,
1669 : : const struct rte_mbuf *pkt,
1670 : : uint32_t *subport, uint32_t *pipe,
1671 : : uint32_t *traffic_class, uint32_t *queue)
1672 : : {
1673 : : uint32_t queue_id = rte_mbuf_sched_queue_get(pkt);
1674 : :
1675 : 10 : *subport = queue_id >> (port->n_pipes_per_subport_log2 + 4);
1676 : 10 : *pipe = (queue_id >> 4) &
1677 : 10 : (port->subports[*subport]->n_pipes_per_subport_enabled - 1);
1678 : 10 : *traffic_class = rte_sched_port_pipe_tc(port, queue_id);
1679 : 10 : *queue = rte_sched_port_tc_queue(port, queue_id);
1680 : 10 : }
1681 : :
1682 : : enum rte_color
1683 : 10 : rte_sched_port_pkt_read_color(const struct rte_mbuf *pkt)
1684 : : {
1685 : 10 : return (enum rte_color)rte_mbuf_sched_color_get(pkt);
1686 : : }
1687 : :
1688 : : int
1689 : 1 : rte_sched_subport_read_stats(struct rte_sched_port *port,
1690 : : uint32_t subport_id,
1691 : : struct rte_sched_subport_stats *stats,
1692 : : uint32_t *tc_ov)
1693 : : {
1694 : : struct rte_sched_subport *s;
1695 : :
1696 : : /* Check user parameters */
1697 [ - + ]: 1 : if (port == NULL) {
1698 : 0 : SCHED_LOG(ERR,
1699 : : "%s: Incorrect value for parameter port", __func__);
1700 : 0 : return -EINVAL;
1701 : : }
1702 : :
1703 [ - + ]: 1 : if (subport_id >= port->n_subports_per_port) {
1704 : 0 : SCHED_LOG(ERR,
1705 : : "%s: Incorrect value for subport id", __func__);
1706 : 0 : return -EINVAL;
1707 : : }
1708 : :
1709 [ - + ]: 1 : if (stats == NULL) {
1710 : 0 : SCHED_LOG(ERR,
1711 : : "%s: Incorrect value for parameter stats", __func__);
1712 : 0 : return -EINVAL;
1713 : : }
1714 : :
1715 [ - + ]: 1 : if (tc_ov == NULL) {
1716 : 0 : SCHED_LOG(ERR,
1717 : : "%s: Incorrect value for tc_ov", __func__);
1718 : 0 : return -EINVAL;
1719 : : }
1720 : :
1721 : 1 : s = port->subports[subport_id];
1722 : :
1723 : : /* Copy subport stats and clear */
1724 : 1 : memcpy(stats, &s->stats, sizeof(struct rte_sched_subport_stats));
1725 : : memset(&s->stats, 0, sizeof(struct rte_sched_subport_stats));
1726 : :
1727 : : /* Subport TC oversubscription status */
1728 : 1 : *tc_ov = s->tc_ov;
1729 : :
1730 : 1 : return 0;
1731 : : }
1732 : :
1733 : : int
1734 : 1 : rte_sched_queue_read_stats(struct rte_sched_port *port,
1735 : : uint32_t queue_id,
1736 : : struct rte_sched_queue_stats *stats,
1737 : : uint16_t *qlen)
1738 : : {
1739 : : struct rte_sched_subport *s;
1740 : : struct rte_sched_queue *q;
1741 : : struct rte_sched_queue_extra *qe;
1742 : : uint32_t subport_id, subport_qmask, subport_qindex;
1743 : :
1744 : : /* Check user parameters */
1745 [ - + ]: 1 : if (port == NULL) {
1746 : 0 : SCHED_LOG(ERR,
1747 : : "%s: Incorrect value for parameter port", __func__);
1748 : 0 : return -EINVAL;
1749 : : }
1750 : :
1751 [ - + ]: 1 : if (queue_id >= rte_sched_port_queues_per_port(port)) {
1752 : 0 : SCHED_LOG(ERR,
1753 : : "%s: Incorrect value for queue id", __func__);
1754 : 0 : return -EINVAL;
1755 : : }
1756 : :
1757 [ - + ]: 1 : if (stats == NULL) {
1758 : 0 : SCHED_LOG(ERR,
1759 : : "%s: Incorrect value for parameter stats", __func__);
1760 : 0 : return -EINVAL;
1761 : : }
1762 : :
1763 [ - + ]: 1 : if (qlen == NULL) {
1764 : 0 : SCHED_LOG(ERR,
1765 : : "%s: Incorrect value for parameter qlen", __func__);
1766 : 0 : return -EINVAL;
1767 : : }
1768 : 1 : subport_qmask = port->n_pipes_per_subport_log2 + 4;
1769 : 1 : subport_id = (queue_id >> subport_qmask) & (port->n_subports_per_port - 1);
1770 : :
1771 : 1 : s = port->subports[subport_id];
1772 : 1 : subport_qindex = ((1 << subport_qmask) - 1) & queue_id;
1773 : 1 : q = s->queue + subport_qindex;
1774 : 1 : qe = s->queue_extra + subport_qindex;
1775 : :
1776 : : /* Copy queue stats and clear */
1777 : 1 : memcpy(stats, &qe->stats, sizeof(struct rte_sched_queue_stats));
1778 : : memset(&qe->stats, 0, sizeof(struct rte_sched_queue_stats));
1779 : :
1780 : : /* Queue length */
1781 : 1 : *qlen = q->qw - q->qr;
1782 : :
1783 : 1 : return 0;
1784 : : }
1785 : :
1786 : : #ifdef RTE_SCHED_DEBUG
1787 : :
1788 : : static inline int
1789 : : rte_sched_port_queue_is_empty(struct rte_sched_subport *subport,
1790 : : uint32_t qindex)
1791 : : {
1792 : : struct rte_sched_queue *queue = subport->queue + qindex;
1793 : :
1794 : : return queue->qr == queue->qw;
1795 : : }
1796 : :
1797 : : #endif /* RTE_SCHED_DEBUG */
1798 : :
1799 : : static inline void
1800 : : rte_sched_port_update_subport_stats(struct rte_sched_port *port,
1801 : : struct rte_sched_subport *subport,
1802 : : uint32_t qindex,
1803 : : struct rte_mbuf *pkt)
1804 : : {
1805 : 10 : uint32_t tc_index = rte_sched_port_pipe_tc(port, qindex);
1806 : 10 : uint32_t pkt_len = pkt->pkt_len;
1807 : :
1808 : 10 : subport->stats.n_pkts_tc[tc_index] += 1;
1809 : 10 : subport->stats.n_bytes_tc[tc_index] += pkt_len;
1810 : : }
1811 : :
1812 : : static inline void
1813 : : rte_sched_port_update_subport_stats_on_drop(struct rte_sched_port *port,
1814 : : struct rte_sched_subport *subport,
1815 : : uint32_t qindex,
1816 : : struct rte_mbuf *pkt,
1817 : : uint32_t n_pkts_cman_dropped)
1818 : : {
1819 : 0 : uint32_t tc_index = rte_sched_port_pipe_tc(port, qindex);
1820 : 0 : uint32_t pkt_len = pkt->pkt_len;
1821 : :
1822 : 0 : subport->stats.n_pkts_tc_dropped[tc_index] += 1;
1823 : 0 : subport->stats.n_bytes_tc_dropped[tc_index] += pkt_len;
1824 : 0 : subport->stats.n_pkts_cman_dropped[tc_index] += n_pkts_cman_dropped;
1825 : : }
1826 : :
1827 : : static inline void
1828 : : rte_sched_port_update_queue_stats(struct rte_sched_subport *subport,
1829 : : uint32_t qindex,
1830 : : struct rte_mbuf *pkt)
1831 : : {
1832 : 10 : struct rte_sched_queue_extra *qe = subport->queue_extra + qindex;
1833 : : uint32_t pkt_len = pkt->pkt_len;
1834 : :
1835 : 10 : qe->stats.n_pkts += 1;
1836 : 10 : qe->stats.n_bytes += pkt_len;
1837 : : }
1838 : :
1839 : : static inline void
1840 : : rte_sched_port_update_queue_stats_on_drop(struct rte_sched_subport *subport,
1841 : : uint32_t qindex,
1842 : : struct rte_mbuf *pkt,
1843 : : uint32_t n_pkts_cman_dropped)
1844 : : {
1845 : 0 : struct rte_sched_queue_extra *qe = subport->queue_extra + qindex;
1846 : : uint32_t pkt_len = pkt->pkt_len;
1847 : :
1848 : 0 : qe->stats.n_pkts_dropped += 1;
1849 : 0 : qe->stats.n_bytes_dropped += pkt_len;
1850 : 0 : if (subport->cman_enabled)
1851 : 0 : qe->stats.n_pkts_cman_dropped += n_pkts_cman_dropped;
1852 : : }
1853 : :
1854 : : static inline int
1855 : 10 : rte_sched_port_cman_drop(struct rte_sched_port *port,
1856 : : struct rte_sched_subport *subport,
1857 : : struct rte_mbuf *pkt,
1858 : : uint32_t qindex,
1859 : : uint16_t qlen)
1860 : : {
1861 [ - + ]: 10 : if (!subport->cman_enabled)
1862 : : return 0;
1863 : :
1864 : : struct rte_sched_queue_extra *qe;
1865 : : uint32_t tc_index;
1866 : :
1867 : 0 : tc_index = rte_sched_port_pipe_tc(port, qindex);
1868 : 0 : qe = subport->queue_extra + qindex;
1869 : :
1870 : : /* RED */
1871 [ # # ]: 0 : if (subport->cman == RTE_SCHED_CMAN_RED) {
1872 : : struct rte_red_config *red_cfg;
1873 : : struct rte_red *red;
1874 : : enum rte_color color;
1875 : :
1876 : 0 : color = rte_sched_port_pkt_read_color(pkt);
1877 : 0 : red_cfg = &subport->red_config[tc_index][color];
1878 : :
1879 [ # # ]: 0 : if ((red_cfg->min_th | red_cfg->max_th) == 0)
1880 : : return 0;
1881 : :
1882 : 0 : red = &qe->red;
1883 : :
1884 : 0 : return rte_red_enqueue(red_cfg, red, qlen, port->time);
1885 : : }
1886 : :
1887 : : /* PIE */
1888 : 0 : struct rte_pie_config *pie_cfg = &subport->pie_config[tc_index];
1889 : 0 : struct rte_pie *pie = &qe->pie;
1890 : :
1891 : 0 : return rte_pie_enqueue(pie_cfg, pie, qlen, pkt->pkt_len, port->time_cpu_cycles);
1892 : : }
1893 : :
1894 : : static inline void
1895 : : rte_sched_port_red_set_queue_empty_timestamp(struct rte_sched_port *port,
1896 : : struct rte_sched_subport *subport, uint32_t qindex)
1897 : : {
1898 [ - + - - ]: 1 : if (subport->cman_enabled && subport->cman == RTE_SCHED_CMAN_RED) {
1899 : 0 : struct rte_sched_queue_extra *qe = subport->queue_extra + qindex;
1900 : : struct rte_red *red = &qe->red;
1901 : :
1902 : 0 : rte_red_mark_queue_empty(red, port->time);
1903 : : }
1904 : : }
1905 : :
1906 : : static inline void
1907 : 10 : rte_sched_port_pie_dequeue(struct rte_sched_subport *subport,
1908 : : uint32_t qindex, uint32_t pkt_len, uint64_t time) {
1909 [ - + - - ]: 10 : if (subport->cman_enabled && subport->cman == RTE_SCHED_CMAN_PIE) {
1910 : 0 : struct rte_sched_queue_extra *qe = subport->queue_extra + qindex;
1911 : 0 : struct rte_pie *pie = &qe->pie;
1912 : :
1913 : : /* Update queue length */
1914 : 0 : pie->qlen -= 1;
1915 : 0 : pie->qlen_bytes -= pkt_len;
1916 : :
1917 : 0 : rte_pie_dequeue(pie, pkt_len, time);
1918 : : }
1919 : 10 : }
1920 : :
1921 : : #ifdef RTE_SCHED_DEBUG
1922 : :
1923 : : static inline void
1924 : : debug_check_queue_slab(struct rte_sched_subport *subport, uint32_t bmp_pos,
1925 : : uint64_t bmp_slab)
1926 : : {
1927 : : uint64_t mask;
1928 : : uint32_t i, panic;
1929 : :
1930 : : if (bmp_slab == 0)
1931 : : rte_panic("Empty slab at position %u\n", bmp_pos);
1932 : :
1933 : : panic = 0;
1934 : : for (i = 0, mask = 1; i < 64; i++, mask <<= 1) {
1935 : : if (mask & bmp_slab) {
1936 : : if (rte_sched_port_queue_is_empty(subport, bmp_pos + i)) {
1937 : : printf("Queue %u (slab offset %u) is empty\n", bmp_pos + i, i);
1938 : : panic = 1;
1939 : : }
1940 : : }
1941 : : }
1942 : :
1943 : : if (panic)
1944 : : rte_panic("Empty queues in slab 0x%" PRIx64 "starting at position %u\n",
1945 : : bmp_slab, bmp_pos);
1946 : : }
1947 : :
1948 : : #endif /* RTE_SCHED_DEBUG */
1949 : :
1950 : : static inline struct rte_sched_subport *
1951 : : rte_sched_port_subport(struct rte_sched_port *port,
1952 : : struct rte_mbuf *pkt)
1953 : : {
1954 : : uint32_t queue_id = rte_mbuf_sched_queue_get(pkt);
1955 : 6 : uint32_t subport_id = queue_id >> (port->n_pipes_per_subport_log2 + 4);
1956 : :
1957 : 6 : return port->subports[subport_id];
1958 : : }
1959 : :
1960 : : static inline uint32_t
1961 : : rte_sched_port_enqueue_qptrs_prefetch0(struct rte_sched_subport *subport,
1962 : : struct rte_mbuf *pkt, uint32_t subport_qmask)
1963 : : {
1964 : : struct rte_sched_queue *q;
1965 : : struct rte_sched_queue_extra *qe;
1966 : : uint32_t qindex = rte_mbuf_sched_queue_get(pkt);
1967 : 11 : uint32_t subport_queue_id = subport_qmask & qindex;
1968 : :
1969 : 11 : q = subport->queue + subport_queue_id;
1970 : : rte_prefetch0(q);
1971 : 11 : qe = subport->queue_extra + subport_queue_id;
1972 : : rte_prefetch0(qe);
1973 : :
1974 : : return subport_queue_id;
1975 : : }
1976 : :
1977 : : static inline void
1978 : : rte_sched_port_enqueue_qwa_prefetch0(struct rte_sched_port *port,
1979 : : struct rte_sched_subport *subport,
1980 : : uint32_t qindex,
1981 : : struct rte_mbuf **qbase)
1982 : : {
1983 : : struct rte_sched_queue *q;
1984 : : struct rte_mbuf **q_qw;
1985 : : uint16_t qsize;
1986 : :
1987 : 9 : q = subport->queue + qindex;
1988 : : qsize = rte_sched_subport_pipe_qsize(port, subport, qindex);
1989 : 10 : q_qw = qbase + (q->qw & (qsize - 1));
1990 : :
1991 : : rte_prefetch0(q_qw);
1992 : 11 : rte_bitmap_prefetch0(subport->bmp, qindex);
1993 : : }
1994 : :
1995 : : static inline int
1996 : 10 : rte_sched_port_enqueue_qwa(struct rte_sched_port *port,
1997 : : struct rte_sched_subport *subport,
1998 : : uint32_t qindex,
1999 : : struct rte_mbuf **qbase,
2000 : : struct rte_mbuf *pkt)
2001 : : {
2002 : : struct rte_sched_queue *q;
2003 : : uint16_t qsize;
2004 : : uint16_t qlen;
2005 : :
2006 : 10 : q = subport->queue + qindex;
2007 : : qsize = rte_sched_subport_pipe_qsize(port, subport, qindex);
2008 : 10 : qlen = q->qw - q->qr;
2009 : :
2010 : : /* Drop the packet (and update drop stats) when queue is full */
2011 [ + - - + ]: 10 : if (unlikely(rte_sched_port_cman_drop(port, subport, pkt, qindex, qlen) ||
2012 : : (qlen >= qsize))) {
2013 : 0 : rte_pktmbuf_free(pkt);
2014 [ # # ]: 0 : rte_sched_port_update_subport_stats_on_drop(port, subport,
2015 : : qindex, pkt, qlen < qsize);
2016 : : rte_sched_port_update_queue_stats_on_drop(subport, qindex, pkt,
2017 : : qlen < qsize);
2018 : 0 : return 0;
2019 : : }
2020 : :
2021 : : /* Enqueue packet */
2022 : 10 : qbase[q->qw & (qsize - 1)] = pkt;
2023 : 10 : q->qw++;
2024 : :
2025 : : /* Activate queue in the subport bitmap */
2026 : 10 : rte_bitmap_set(subport->bmp, qindex);
2027 : :
2028 : : /* Statistics */
2029 : : rte_sched_port_update_subport_stats(port, subport, qindex, pkt);
2030 : : rte_sched_port_update_queue_stats(subport, qindex, pkt);
2031 : :
2032 : 10 : return 1;
2033 : : }
2034 : :
2035 : :
2036 : : /*
2037 : : * The enqueue function implements a 4-level pipeline with each stage
2038 : : * processing two different packets. The purpose of using a pipeline
2039 : : * is to hide the latency of prefetching the data structures. The
2040 : : * naming convention is presented in the diagram below:
2041 : : *
2042 : : * p00 _______ p10 _______ p20 _______ p30 _______
2043 : : * ----->| |----->| |----->| |----->| |----->
2044 : : * | 0 | | 1 | | 2 | | 3 |
2045 : : * ----->|_______|----->|_______|----->|_______|----->|_______|----->
2046 : : * p01 p11 p21 p31
2047 : : */
2048 : : int
2049 : 1 : rte_sched_port_enqueue(struct rte_sched_port *port, struct rte_mbuf **pkts,
2050 : : uint32_t n_pkts)
2051 : : {
2052 : : struct rte_mbuf *pkt00, *pkt01, *pkt10, *pkt11, *pkt20, *pkt21,
2053 : : *pkt30, *pkt31, *pkt_last;
2054 : : struct rte_mbuf **q00_base, **q01_base, **q10_base, **q11_base,
2055 : : **q20_base, **q21_base, **q30_base, **q31_base, **q_last_base;
2056 : : struct rte_sched_subport *subport00, *subport01, *subport10, *subport11,
2057 : : *subport20, *subport21, *subport30, *subport31, *subport_last;
2058 : : uint32_t q00, q01, q10, q11, q20, q21, q30, q31, q_last;
2059 : : uint32_t r00, r01, r10, r11, r20, r21, r30, r31, r_last;
2060 : : uint32_t subport_qmask;
2061 : : uint32_t result, i;
2062 : :
2063 : : result = 0;
2064 : 1 : subport_qmask = (1 << (port->n_pipes_per_subport_log2 + 4)) - 1;
2065 : :
2066 : : /*
2067 : : * Less then 6 input packets available, which is not enough to
2068 : : * feed the pipeline
2069 : : */
2070 [ - + ]: 1 : if (unlikely(n_pkts < 6)) {
2071 : : struct rte_sched_subport *subports[5];
2072 : : struct rte_mbuf **q_base[5];
2073 : : uint32_t q[5];
2074 : :
2075 : : /* Prefetch the mbuf structure of each packet */
2076 [ # # ]: 0 : for (i = 0; i < n_pkts; i++)
2077 : 0 : rte_prefetch0(pkts[i]);
2078 : :
2079 : : /* Prefetch the subport structure for each packet */
2080 [ # # ]: 0 : for (i = 0; i < n_pkts; i++)
2081 : 0 : subports[i] = rte_sched_port_subport(port, pkts[i]);
2082 : :
2083 : : /* Prefetch the queue structure for each queue */
2084 [ # # ]: 0 : for (i = 0; i < n_pkts; i++)
2085 : 0 : q[i] = rte_sched_port_enqueue_qptrs_prefetch0(subports[i],
2086 : 0 : pkts[i], subport_qmask);
2087 : :
2088 : : /* Prefetch the write pointer location of each queue */
2089 [ # # ]: 0 : for (i = 0; i < n_pkts; i++) {
2090 : 0 : q_base[i] = rte_sched_subport_pipe_qbase(subports[i], q[i]);
2091 : : rte_sched_port_enqueue_qwa_prefetch0(port, subports[i],
2092 : : q[i], q_base[i]);
2093 : : }
2094 : :
2095 : : /* Write each packet to its queue */
2096 [ # # ]: 0 : for (i = 0; i < n_pkts; i++)
2097 : 0 : result += rte_sched_port_enqueue_qwa(port, subports[i],
2098 : 0 : q[i], q_base[i], pkts[i]);
2099 : :
2100 : 0 : return result;
2101 : : }
2102 : :
2103 : : /* Feed the first 3 stages of the pipeline (6 packets needed) */
2104 : 1 : pkt20 = pkts[0];
2105 : 1 : pkt21 = pkts[1];
2106 : : rte_prefetch0(pkt20);
2107 : : rte_prefetch0(pkt21);
2108 : :
2109 : 1 : pkt10 = pkts[2];
2110 : 1 : pkt11 = pkts[3];
2111 : : rte_prefetch0(pkt10);
2112 : : rte_prefetch0(pkt11);
2113 : :
2114 : : subport20 = rte_sched_port_subport(port, pkt20);
2115 : : subport21 = rte_sched_port_subport(port, pkt21);
2116 : : q20 = rte_sched_port_enqueue_qptrs_prefetch0(subport20,
2117 : : pkt20, subport_qmask);
2118 : : q21 = rte_sched_port_enqueue_qptrs_prefetch0(subport21,
2119 : : pkt21, subport_qmask);
2120 : :
2121 : 1 : pkt00 = pkts[4];
2122 : 1 : pkt01 = pkts[5];
2123 : : rte_prefetch0(pkt00);
2124 : : rte_prefetch0(pkt01);
2125 : :
2126 : : subport10 = rte_sched_port_subport(port, pkt10);
2127 : : subport11 = rte_sched_port_subport(port, pkt11);
2128 : : q10 = rte_sched_port_enqueue_qptrs_prefetch0(subport10,
2129 : : pkt10, subport_qmask);
2130 : : q11 = rte_sched_port_enqueue_qptrs_prefetch0(subport11,
2131 : : pkt11, subport_qmask);
2132 : :
2133 : : q20_base = rte_sched_subport_pipe_qbase(subport20, q20);
2134 : : q21_base = rte_sched_subport_pipe_qbase(subport21, q21);
2135 : : rte_sched_port_enqueue_qwa_prefetch0(port, subport20, q20, q20_base);
2136 : : rte_sched_port_enqueue_qwa_prefetch0(port, subport21, q21, q21_base);
2137 : :
2138 : : /* Run the pipeline */
2139 [ + + ]: 3 : for (i = 6; i < (n_pkts & (~1)); i += 2) {
2140 : : /* Propagate stage inputs */
2141 : : pkt30 = pkt20;
2142 : : pkt31 = pkt21;
2143 : : pkt20 = pkt10;
2144 : : pkt21 = pkt11;
2145 : : pkt10 = pkt00;
2146 : : pkt11 = pkt01;
2147 : : q30 = q20;
2148 : : q31 = q21;
2149 : : q20 = q10;
2150 : : q21 = q11;
2151 : : subport30 = subport20;
2152 : : subport31 = subport21;
2153 : : subport20 = subport10;
2154 : : subport21 = subport11;
2155 : : q30_base = q20_base;
2156 : : q31_base = q21_base;
2157 : :
2158 : : /* Stage 0: Get packets in */
2159 : 2 : pkt00 = pkts[i];
2160 : 2 : pkt01 = pkts[i + 1];
2161 : : rte_prefetch0(pkt00);
2162 : : rte_prefetch0(pkt01);
2163 : :
2164 : : /* Stage 1: Prefetch subport and queue structure storing queue pointers */
2165 : : subport10 = rte_sched_port_subport(port, pkt10);
2166 : : subport11 = rte_sched_port_subport(port, pkt11);
2167 : : q10 = rte_sched_port_enqueue_qptrs_prefetch0(subport10,
2168 : : pkt10, subport_qmask);
2169 : : q11 = rte_sched_port_enqueue_qptrs_prefetch0(subport11,
2170 : : pkt11, subport_qmask);
2171 : :
2172 : : /* Stage 2: Prefetch queue write location */
2173 : : q20_base = rte_sched_subport_pipe_qbase(subport20, q20);
2174 : : q21_base = rte_sched_subport_pipe_qbase(subport21, q21);
2175 : : rte_sched_port_enqueue_qwa_prefetch0(port, subport20, q20, q20_base);
2176 : : rte_sched_port_enqueue_qwa_prefetch0(port, subport21, q21, q21_base);
2177 : :
2178 : : /* Stage 3: Write packet to queue and activate queue */
2179 : 2 : r30 = rte_sched_port_enqueue_qwa(port, subport30,
2180 : : q30, q30_base, pkt30);
2181 : 2 : r31 = rte_sched_port_enqueue_qwa(port, subport31,
2182 : : q31, q31_base, pkt31);
2183 : 2 : result += r30 + r31;
2184 : : }
2185 : :
2186 : : /*
2187 : : * Drain the pipeline (exactly 6 packets).
2188 : : * Handle the last packet in the case
2189 : : * of an odd number of input packets.
2190 : : */
2191 : 1 : pkt_last = pkts[n_pkts - 1];
2192 : : rte_prefetch0(pkt_last);
2193 : :
2194 : : subport00 = rte_sched_port_subport(port, pkt00);
2195 : : subport01 = rte_sched_port_subport(port, pkt01);
2196 : : q00 = rte_sched_port_enqueue_qptrs_prefetch0(subport00,
2197 : : pkt00, subport_qmask);
2198 : : q01 = rte_sched_port_enqueue_qptrs_prefetch0(subport01,
2199 : : pkt01, subport_qmask);
2200 : :
2201 : : q10_base = rte_sched_subport_pipe_qbase(subport10, q10);
2202 : : q11_base = rte_sched_subport_pipe_qbase(subport11, q11);
2203 : : rte_sched_port_enqueue_qwa_prefetch0(port, subport10, q10, q10_base);
2204 : : rte_sched_port_enqueue_qwa_prefetch0(port, subport11, q11, q11_base);
2205 : :
2206 : 1 : r20 = rte_sched_port_enqueue_qwa(port, subport20,
2207 : : q20, q20_base, pkt20);
2208 : 1 : r21 = rte_sched_port_enqueue_qwa(port, subport21,
2209 : : q21, q21_base, pkt21);
2210 : 1 : result += r20 + r21;
2211 : :
2212 : : subport_last = rte_sched_port_subport(port, pkt_last);
2213 : : q_last = rte_sched_port_enqueue_qptrs_prefetch0(subport_last,
2214 : : pkt_last, subport_qmask);
2215 : :
2216 : : q00_base = rte_sched_subport_pipe_qbase(subport00, q00);
2217 : : q01_base = rte_sched_subport_pipe_qbase(subport01, q01);
2218 : : rte_sched_port_enqueue_qwa_prefetch0(port, subport00, q00, q00_base);
2219 : : rte_sched_port_enqueue_qwa_prefetch0(port, subport01, q01, q01_base);
2220 : :
2221 : 1 : r10 = rte_sched_port_enqueue_qwa(port, subport10, q10,
2222 : : q10_base, pkt10);
2223 : 1 : r11 = rte_sched_port_enqueue_qwa(port, subport11, q11,
2224 : : q11_base, pkt11);
2225 : 1 : result += r10 + r11;
2226 : :
2227 : : q_last_base = rte_sched_subport_pipe_qbase(subport_last, q_last);
2228 : : rte_sched_port_enqueue_qwa_prefetch0(port, subport_last,
2229 : : q_last, q_last_base);
2230 : :
2231 : 1 : r00 = rte_sched_port_enqueue_qwa(port, subport00, q00,
2232 : : q00_base, pkt00);
2233 : 1 : r01 = rte_sched_port_enqueue_qwa(port, subport01, q01,
2234 : : q01_base, pkt01);
2235 : 1 : result += r00 + r01;
2236 : :
2237 [ - + ]: 1 : if (n_pkts & 1) {
2238 : 0 : r_last = rte_sched_port_enqueue_qwa(port, subport_last,
2239 : : q_last, q_last_base, pkt_last);
2240 : 0 : result += r_last;
2241 : : }
2242 : :
2243 : 1 : return result;
2244 : : }
2245 : :
2246 : : static inline uint64_t
2247 : 0 : grinder_tc_ov_credits_update(struct rte_sched_port *port,
2248 : : struct rte_sched_subport *subport, uint32_t pos)
2249 : : {
2250 : 0 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2251 : 0 : struct rte_sched_subport_profile *sp = grinder->subport_params;
2252 : : uint64_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
2253 : : uint64_t tc_consumption = 0, tc_ov_consumption_max;
2254 : 0 : uint64_t tc_ov_wm = subport->tc_ov_wm;
2255 : : uint32_t i;
2256 : :
2257 [ # # ]: 0 : if (subport->tc_ov == 0)
2258 : 0 : return subport->tc_ov_wm_max;
2259 : :
2260 [ # # ]: 0 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
2261 : 0 : tc_ov_consumption[i] = sp->tc_credits_per_period[i]
2262 : 0 : - subport->tc_credits[i];
2263 : 0 : tc_consumption += tc_ov_consumption[i];
2264 : : }
2265 : :
2266 : : tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
2267 : 0 : sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
2268 : 0 : subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
2269 : :
2270 : 0 : tc_ov_consumption_max =
2271 : : sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
2272 : : tc_consumption;
2273 : :
2274 : 0 : if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
2275 [ # # ]: 0 : (tc_ov_consumption_max - port->mtu)) {
2276 : 0 : tc_ov_wm -= tc_ov_wm >> 7;
2277 : 0 : if (tc_ov_wm < subport->tc_ov_wm_min)
2278 : : tc_ov_wm = subport->tc_ov_wm_min;
2279 : :
2280 : 0 : return tc_ov_wm;
2281 : : }
2282 : :
2283 : 0 : tc_ov_wm += (tc_ov_wm >> 7) + 1;
2284 : 0 : if (tc_ov_wm > subport->tc_ov_wm_max)
2285 : : tc_ov_wm = subport->tc_ov_wm_max;
2286 : :
2287 : : return tc_ov_wm;
2288 : : }
2289 : :
2290 : : static inline void
2291 : 0 : grinder_credits_update(struct rte_sched_port *port,
2292 : : struct rte_sched_subport *subport, uint32_t pos)
2293 : : {
2294 : 0 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2295 : 0 : struct rte_sched_pipe *pipe = grinder->pipe;
2296 : 0 : struct rte_sched_pipe_profile *params = grinder->pipe_params;
2297 : 0 : struct rte_sched_subport_profile *sp = grinder->subport_params;
2298 : : uint64_t n_periods;
2299 : : uint32_t i;
2300 : :
2301 : : /* Subport TB */
2302 : 0 : n_periods = (port->time - subport->tb_time) / sp->tb_period;
2303 : 0 : subport->tb_credits += n_periods * sp->tb_credits_per_period;
2304 : 0 : subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
2305 : 0 : subport->tb_time += n_periods * sp->tb_period;
2306 : :
2307 : : /* Pipe TB */
2308 : 0 : n_periods = (port->time - pipe->tb_time) / params->tb_period;
2309 : 0 : pipe->tb_credits += n_periods * params->tb_credits_per_period;
2310 : 0 : pipe->tb_credits = RTE_MIN(pipe->tb_credits, params->tb_size);
2311 : 0 : pipe->tb_time += n_periods * params->tb_period;
2312 : :
2313 : : /* Subport TCs */
2314 [ # # ]: 0 : if (unlikely(port->time >= subport->tc_time)) {
2315 [ # # ]: 0 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
2316 : 0 : subport->tc_credits[i] = sp->tc_credits_per_period[i];
2317 : :
2318 : 0 : subport->tc_time = port->time + sp->tc_period;
2319 : : }
2320 : :
2321 : : /* Pipe TCs */
2322 [ # # ]: 0 : if (unlikely(port->time >= pipe->tc_time)) {
2323 [ # # ]: 0 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
2324 : 0 : pipe->tc_credits[i] = params->tc_credits_per_period[i];
2325 : 0 : pipe->tc_time = port->time + params->tc_period;
2326 : : }
2327 : 0 : }
2328 : :
2329 : : static inline void
2330 : 1 : grinder_credits_update_with_tc_ov(struct rte_sched_port *port,
2331 : : struct rte_sched_subport *subport, uint32_t pos)
2332 : : {
2333 : 1 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2334 : 1 : struct rte_sched_pipe *pipe = grinder->pipe;
2335 : 1 : struct rte_sched_pipe_profile *params = grinder->pipe_params;
2336 : 1 : struct rte_sched_subport_profile *sp = grinder->subport_params;
2337 : : uint64_t n_periods;
2338 : : uint32_t i;
2339 : :
2340 : : /* Subport TB */
2341 : 1 : n_periods = (port->time - subport->tb_time) / sp->tb_period;
2342 : 1 : subport->tb_credits += n_periods * sp->tb_credits_per_period;
2343 : 1 : subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
2344 : 1 : subport->tb_time += n_periods * sp->tb_period;
2345 : :
2346 : : /* Pipe TB */
2347 : 1 : n_periods = (port->time - pipe->tb_time) / params->tb_period;
2348 : 1 : pipe->tb_credits += n_periods * params->tb_credits_per_period;
2349 : 1 : pipe->tb_credits = RTE_MIN(pipe->tb_credits, params->tb_size);
2350 : 1 : pipe->tb_time += n_periods * params->tb_period;
2351 : :
2352 : : /* Subport TCs */
2353 [ - + ]: 1 : if (unlikely(port->time >= subport->tc_time)) {
2354 : 0 : subport->tc_ov_wm =
2355 : 0 : grinder_tc_ov_credits_update(port, subport, pos);
2356 : :
2357 [ # # ]: 0 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
2358 : 0 : subport->tc_credits[i] = sp->tc_credits_per_period[i];
2359 : :
2360 : 0 : subport->tc_time = port->time + sp->tc_period;
2361 : 0 : subport->tc_ov_period_id++;
2362 : : }
2363 : :
2364 : : /* Pipe TCs */
2365 [ - + ]: 1 : if (unlikely(port->time >= pipe->tc_time)) {
2366 [ # # ]: 0 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
2367 : 0 : pipe->tc_credits[i] = params->tc_credits_per_period[i];
2368 : 0 : pipe->tc_time = port->time + params->tc_period;
2369 : : }
2370 : :
2371 : : /* Pipe TCs - Oversubscription */
2372 [ - + ]: 1 : if (unlikely(pipe->tc_ov_period_id != subport->tc_ov_period_id)) {
2373 : 0 : pipe->tc_ov_credits = subport->tc_ov_wm * params->tc_ov_weight;
2374 : :
2375 : 0 : pipe->tc_ov_period_id = subport->tc_ov_period_id;
2376 : : }
2377 : 1 : }
2378 : :
2379 : : static inline int
2380 : 0 : grinder_credits_check(struct rte_sched_port *port,
2381 : : struct rte_sched_subport *subport, uint32_t pos)
2382 : : {
2383 : 0 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2384 : 0 : struct rte_sched_pipe *pipe = grinder->pipe;
2385 : 0 : struct rte_mbuf *pkt = grinder->pkt;
2386 : 0 : uint32_t tc_index = grinder->tc_index;
2387 : 0 : uint64_t pkt_len = pkt->pkt_len + port->frame_overhead;
2388 : 0 : uint64_t subport_tb_credits = subport->tb_credits;
2389 : 0 : uint64_t subport_tc_credits = subport->tc_credits[tc_index];
2390 : 0 : uint64_t pipe_tb_credits = pipe->tb_credits;
2391 : 0 : uint64_t pipe_tc_credits = pipe->tc_credits[tc_index];
2392 : : int enough_credits;
2393 : :
2394 : : /* Check pipe and subport credits */
2395 : : enough_credits = (pkt_len <= subport_tb_credits) &&
2396 : : (pkt_len <= subport_tc_credits) &&
2397 [ # # # # ]: 0 : (pkt_len <= pipe_tb_credits) &&
2398 : : (pkt_len <= pipe_tc_credits);
2399 : :
2400 : : if (!enough_credits)
2401 : : return 0;
2402 : :
2403 : : /* Update pipe and subport credits */
2404 : 0 : subport->tb_credits -= pkt_len;
2405 : 0 : subport->tc_credits[tc_index] -= pkt_len;
2406 : 0 : pipe->tb_credits -= pkt_len;
2407 : 0 : pipe->tc_credits[tc_index] -= pkt_len;
2408 : :
2409 : 0 : return 1;
2410 : : }
2411 : :
2412 : : static inline int
2413 : 10 : grinder_credits_check_with_tc_ov(struct rte_sched_port *port,
2414 : : struct rte_sched_subport *subport, uint32_t pos)
2415 : : {
2416 : 10 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2417 : 10 : struct rte_sched_pipe *pipe = grinder->pipe;
2418 : 10 : struct rte_mbuf *pkt = grinder->pkt;
2419 : 10 : uint32_t tc_index = grinder->tc_index;
2420 : 10 : uint64_t pkt_len = pkt->pkt_len + port->frame_overhead;
2421 : 10 : uint64_t subport_tb_credits = subport->tb_credits;
2422 : 10 : uint64_t subport_tc_credits = subport->tc_credits[tc_index];
2423 : 10 : uint64_t pipe_tb_credits = pipe->tb_credits;
2424 : 10 : uint64_t pipe_tc_credits = pipe->tc_credits[tc_index];
2425 : : uint64_t pipe_tc_ov_mask1[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
2426 : 10 : uint64_t pipe_tc_ov_mask2[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE] = {0};
2427 : : uint64_t pipe_tc_ov_credits;
2428 : : uint32_t i;
2429 : : int enough_credits;
2430 : :
2431 [ + + ]: 140 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
2432 : 130 : pipe_tc_ov_mask1[i] = ~0LLU;
2433 : :
2434 : 10 : pipe_tc_ov_mask1[RTE_SCHED_TRAFFIC_CLASS_BE] = pipe->tc_ov_credits;
2435 : 10 : pipe_tc_ov_mask2[RTE_SCHED_TRAFFIC_CLASS_BE] = ~0LLU;
2436 : 10 : pipe_tc_ov_credits = pipe_tc_ov_mask1[tc_index];
2437 : :
2438 : : /* Check pipe and subport credits */
2439 : : enough_credits = (pkt_len <= subport_tb_credits) &&
2440 : : (pkt_len <= subport_tc_credits) &&
2441 [ + - ]: 10 : (pkt_len <= pipe_tb_credits) &&
2442 [ + - + - ]: 20 : (pkt_len <= pipe_tc_credits) &&
2443 : : (pkt_len <= pipe_tc_ov_credits);
2444 : :
2445 : : if (!enough_credits)
2446 : : return 0;
2447 : :
2448 : : /* Update pipe and subport credits */
2449 : 10 : subport->tb_credits -= pkt_len;
2450 : 10 : subport->tc_credits[tc_index] -= pkt_len;
2451 : 10 : pipe->tb_credits -= pkt_len;
2452 : 10 : pipe->tc_credits[tc_index] -= pkt_len;
2453 : 10 : pipe->tc_ov_credits -= pipe_tc_ov_mask2[tc_index] & pkt_len;
2454 : :
2455 : 10 : return 1;
2456 : : }
2457 : :
2458 : :
2459 : : static inline int
2460 : 10 : grinder_schedule(struct rte_sched_port *port,
2461 : : struct rte_sched_subport *subport, uint32_t pos)
2462 : : {
2463 : 10 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2464 : 10 : struct rte_sched_queue *queue = grinder->queue[grinder->qpos];
2465 : 10 : uint32_t qindex = grinder->qindex[grinder->qpos];
2466 : 10 : struct rte_mbuf *pkt = grinder->pkt;
2467 : 10 : uint32_t pkt_len = pkt->pkt_len + port->frame_overhead;
2468 : : uint32_t be_tc_active;
2469 : :
2470 [ + - ]: 10 : if (subport->tc_ov_enabled) {
2471 [ + - ]: 10 : if (!grinder_credits_check_with_tc_ov(port, subport, pos))
2472 : : return 0;
2473 : : } else {
2474 [ # # ]: 0 : if (!grinder_credits_check(port, subport, pos))
2475 : : return 0;
2476 : : }
2477 : :
2478 : : /* Advance port time */
2479 : 10 : port->time += pkt_len;
2480 : :
2481 : : /* Send packet */
2482 : 10 : port->pkts_out[port->n_pkts_out++] = pkt;
2483 : 10 : queue->qr++;
2484 : :
2485 [ + - ]: 10 : be_tc_active = (grinder->tc_index == RTE_SCHED_TRAFFIC_CLASS_BE) ? ~0x0 : 0x0;
2486 : 10 : grinder->wrr_tokens[grinder->qpos] +=
2487 : 10 : (pkt_len * grinder->wrr_cost[grinder->qpos]) & be_tc_active;
2488 : :
2489 [ + + ]: 10 : if (queue->qr == queue->qw) {
2490 : 1 : rte_bitmap_clear(subport->bmp, qindex);
2491 : 1 : grinder->qmask &= ~(1 << grinder->qpos);
2492 [ - + ]: 1 : if (be_tc_active)
2493 : 0 : grinder->wrr_mask[grinder->qpos] = 0;
2494 : :
2495 : : rte_sched_port_red_set_queue_empty_timestamp(port, subport, qindex);
2496 : : }
2497 : :
2498 : 10 : rte_sched_port_pie_dequeue(subport, qindex, pkt_len, port->time_cpu_cycles);
2499 : :
2500 : : /* Reset pipe loop detection */
2501 : 10 : subport->pipe_loop = RTE_SCHED_PIPE_INVALID;
2502 : 10 : grinder->productive = 1;
2503 : :
2504 : 10 : return 1;
2505 : : }
2506 : :
2507 : : static inline int
2508 : : grinder_pipe_exists(struct rte_sched_subport *subport, uint32_t base_pipe)
2509 : : {
2510 : : uint32_t i;
2511 : :
2512 [ + + ]: 93 : for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++) {
2513 [ + + ]: 92 : if (subport->grinder_base_bmp_pos[i] == base_pipe)
2514 : : return 1;
2515 : : }
2516 : :
2517 : : return 0;
2518 : : }
2519 : :
2520 : : static inline void
2521 : 1 : grinder_pcache_populate(struct rte_sched_subport *subport,
2522 : : uint32_t pos, uint32_t bmp_pos, uint64_t bmp_slab)
2523 : : {
2524 : 1 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2525 : : uint16_t w[4];
2526 : :
2527 : : grinder->pcache_w = 0;
2528 : 1 : grinder->pcache_r = 0;
2529 : :
2530 : 1 : w[0] = (uint16_t) bmp_slab;
2531 : 1 : w[1] = (uint16_t) (bmp_slab >> 16);
2532 : 1 : w[2] = (uint16_t) (bmp_slab >> 32);
2533 : 1 : w[3] = (uint16_t) (bmp_slab >> 48);
2534 : :
2535 : 1 : grinder->pcache_qmask[grinder->pcache_w] = w[0];
2536 : 1 : grinder->pcache_qindex[grinder->pcache_w] = bmp_pos;
2537 : 1 : grinder->pcache_w += (w[0] != 0);
2538 : :
2539 : 1 : grinder->pcache_qmask[grinder->pcache_w] = w[1];
2540 : 1 : grinder->pcache_qindex[grinder->pcache_w] = bmp_pos + 16;
2541 : 1 : grinder->pcache_w += (w[1] != 0);
2542 : :
2543 : 1 : grinder->pcache_qmask[grinder->pcache_w] = w[2];
2544 : 1 : grinder->pcache_qindex[grinder->pcache_w] = bmp_pos + 32;
2545 : 1 : grinder->pcache_w += (w[2] != 0);
2546 : :
2547 : 1 : grinder->pcache_qmask[grinder->pcache_w] = w[3];
2548 : 1 : grinder->pcache_qindex[grinder->pcache_w] = bmp_pos + 48;
2549 : 1 : grinder->pcache_w += (w[3] != 0);
2550 : 1 : }
2551 : :
2552 : : static inline void
2553 : 1 : grinder_tccache_populate(struct rte_sched_subport *subport,
2554 : : uint32_t pos, uint32_t qindex, uint16_t qmask)
2555 : : {
2556 : 1 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2557 : : uint8_t b, i;
2558 : :
2559 : 1 : grinder->tccache_w = 0;
2560 : 1 : grinder->tccache_r = 0;
2561 : :
2562 [ + + ]: 13 : for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
2563 : 12 : b = (uint8_t) ((qmask >> i) & 0x1);
2564 : 12 : grinder->tccache_qmask[grinder->tccache_w] = b;
2565 : 12 : grinder->tccache_qindex[grinder->tccache_w] = qindex + i;
2566 : 12 : grinder->tccache_w += (b != 0);
2567 : : }
2568 : :
2569 : 1 : b = (uint8_t) (qmask >> (RTE_SCHED_TRAFFIC_CLASS_BE));
2570 : 1 : grinder->tccache_qmask[grinder->tccache_w] = b;
2571 : 1 : grinder->tccache_qindex[grinder->tccache_w] = qindex +
2572 : : RTE_SCHED_TRAFFIC_CLASS_BE;
2573 : 1 : grinder->tccache_w += (b != 0);
2574 : 1 : }
2575 : :
2576 : : static inline int
2577 : 2 : grinder_next_tc(struct rte_sched_port *port,
2578 : : struct rte_sched_subport *subport, uint32_t pos)
2579 : : {
2580 : 2 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2581 : : struct rte_mbuf **qbase;
2582 : : uint32_t qindex;
2583 : : uint16_t qsize;
2584 : :
2585 [ + + ]: 2 : if (grinder->tccache_r == grinder->tccache_w)
2586 : : return 0;
2587 : :
2588 : 1 : qindex = grinder->tccache_qindex[grinder->tccache_r];
2589 : : qbase = rte_sched_subport_pipe_qbase(subport, qindex);
2590 : : qsize = rte_sched_subport_pipe_qsize(port, subport, qindex);
2591 : :
2592 : 1 : grinder->tc_index = rte_sched_port_pipe_tc(port, qindex);
2593 : 1 : grinder->qmask = grinder->tccache_qmask[grinder->tccache_r];
2594 : 1 : grinder->qsize = qsize;
2595 : :
2596 [ + - ]: 1 : if (grinder->tc_index < RTE_SCHED_TRAFFIC_CLASS_BE) {
2597 : 1 : grinder->queue[0] = subport->queue + qindex;
2598 : 1 : grinder->qbase[0] = qbase;
2599 : 1 : grinder->qindex[0] = qindex;
2600 : 1 : grinder->tccache_r++;
2601 : :
2602 : 1 : return 1;
2603 : : }
2604 : :
2605 : 0 : grinder->queue[0] = subport->queue + qindex;
2606 : 0 : grinder->queue[1] = subport->queue + qindex + 1;
2607 : 0 : grinder->queue[2] = subport->queue + qindex + 2;
2608 : 0 : grinder->queue[3] = subport->queue + qindex + 3;
2609 : :
2610 : 0 : grinder->qbase[0] = qbase;
2611 : 0 : grinder->qbase[1] = qbase + qsize;
2612 : 0 : grinder->qbase[2] = qbase + 2 * qsize;
2613 : 0 : grinder->qbase[3] = qbase + 3 * qsize;
2614 : :
2615 : 0 : grinder->qindex[0] = qindex;
2616 : 0 : grinder->qindex[1] = qindex + 1;
2617 : 0 : grinder->qindex[2] = qindex + 2;
2618 : 0 : grinder->qindex[3] = qindex + 3;
2619 : :
2620 : 0 : grinder->tccache_r++;
2621 : 0 : return 1;
2622 : : }
2623 : :
2624 : : static inline int
2625 : 86 : grinder_next_pipe(struct rte_sched_port *port,
2626 : : struct rte_sched_subport *subport, uint32_t pos)
2627 : : {
2628 : 86 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2629 : : uint32_t pipe_qindex;
2630 : : uint16_t pipe_qmask;
2631 : :
2632 [ - + ]: 86 : if (grinder->pcache_r < grinder->pcache_w) {
2633 : 0 : pipe_qmask = grinder->pcache_qmask[grinder->pcache_r];
2634 : 0 : pipe_qindex = grinder->pcache_qindex[grinder->pcache_r];
2635 : 0 : grinder->pcache_r++;
2636 : : } else {
2637 : 86 : uint64_t bmp_slab = 0;
2638 : 86 : uint32_t bmp_pos = 0;
2639 : :
2640 : : /* Get another non-empty pipe group */
2641 [ + + ]: 86 : if (unlikely(rte_bitmap_scan(subport->bmp, &bmp_pos, &bmp_slab) <= 0))
2642 : 85 : return 0;
2643 : :
2644 : : #ifdef RTE_SCHED_DEBUG
2645 : : debug_check_queue_slab(subport, bmp_pos, bmp_slab);
2646 : : #endif
2647 : :
2648 : : /* Return if pipe group already in one of the other grinders */
2649 : 85 : subport->grinder_base_bmp_pos[pos] = RTE_SCHED_BMP_POS_INVALID;
2650 [ + + ]: 170 : if (unlikely(grinder_pipe_exists(subport, bmp_pos)))
2651 : : return 0;
2652 : :
2653 : 1 : subport->grinder_base_bmp_pos[pos] = bmp_pos;
2654 : :
2655 : : /* Install new pipe group into grinder's pipe cache */
2656 : 1 : grinder_pcache_populate(subport, pos, bmp_pos, bmp_slab);
2657 : :
2658 : 1 : pipe_qmask = grinder->pcache_qmask[0];
2659 : 1 : pipe_qindex = grinder->pcache_qindex[0];
2660 : 1 : grinder->pcache_r = 1;
2661 : : }
2662 : :
2663 : : /* Install new pipe in the grinder */
2664 : 1 : grinder->pindex = pipe_qindex >> 4;
2665 : 1 : grinder->subport = subport;
2666 : 1 : grinder->pipe = subport->pipe + grinder->pindex;
2667 : 1 : grinder->pipe_params = NULL; /* to be set after the pipe structure is prefetched */
2668 : 1 : grinder->productive = 0;
2669 : :
2670 : 1 : grinder_tccache_populate(subport, pos, pipe_qindex, pipe_qmask);
2671 : 1 : grinder_next_tc(port, subport, pos);
2672 : :
2673 : : /* Check for pipe exhaustion */
2674 [ - + ]: 1 : if (grinder->pindex == subport->pipe_loop) {
2675 : 0 : subport->pipe_exhaustion = 1;
2676 : 0 : subport->pipe_loop = RTE_SCHED_PIPE_INVALID;
2677 : : }
2678 : :
2679 : : return 1;
2680 : : }
2681 : :
2682 : :
2683 : : static inline void
2684 : 0 : grinder_wrr_load(struct rte_sched_subport *subport, uint32_t pos)
2685 : : {
2686 : 0 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2687 : 0 : struct rte_sched_pipe *pipe = grinder->pipe;
2688 : 0 : struct rte_sched_pipe_profile *pipe_params = grinder->pipe_params;
2689 : 0 : uint32_t qmask = grinder->qmask;
2690 : :
2691 : 0 : grinder->wrr_tokens[0] =
2692 : 0 : ((uint16_t) pipe->wrr_tokens[0]) << RTE_SCHED_WRR_SHIFT;
2693 : 0 : grinder->wrr_tokens[1] =
2694 : 0 : ((uint16_t) pipe->wrr_tokens[1]) << RTE_SCHED_WRR_SHIFT;
2695 : 0 : grinder->wrr_tokens[2] =
2696 : 0 : ((uint16_t) pipe->wrr_tokens[2]) << RTE_SCHED_WRR_SHIFT;
2697 : 0 : grinder->wrr_tokens[3] =
2698 : 0 : ((uint16_t) pipe->wrr_tokens[3]) << RTE_SCHED_WRR_SHIFT;
2699 : :
2700 : 0 : grinder->wrr_mask[0] = (qmask & 0x1) * 0xFFFF;
2701 : 0 : grinder->wrr_mask[1] = ((qmask >> 1) & 0x1) * 0xFFFF;
2702 : 0 : grinder->wrr_mask[2] = ((qmask >> 2) & 0x1) * 0xFFFF;
2703 : 0 : grinder->wrr_mask[3] = ((qmask >> 3) & 0x1) * 0xFFFF;
2704 : :
2705 : 0 : grinder->wrr_cost[0] = pipe_params->wrr_cost[0];
2706 : 0 : grinder->wrr_cost[1] = pipe_params->wrr_cost[1];
2707 : 0 : grinder->wrr_cost[2] = pipe_params->wrr_cost[2];
2708 : 0 : grinder->wrr_cost[3] = pipe_params->wrr_cost[3];
2709 : 0 : }
2710 : :
2711 : : static inline void
2712 : 0 : grinder_wrr_store(struct rte_sched_subport *subport, uint32_t pos)
2713 : : {
2714 : 0 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2715 : 0 : struct rte_sched_pipe *pipe = grinder->pipe;
2716 : :
2717 : 0 : pipe->wrr_tokens[0] =
2718 : 0 : (grinder->wrr_tokens[0] & grinder->wrr_mask[0]) >>
2719 : : RTE_SCHED_WRR_SHIFT;
2720 : 0 : pipe->wrr_tokens[1] =
2721 : 0 : (grinder->wrr_tokens[1] & grinder->wrr_mask[1]) >>
2722 : : RTE_SCHED_WRR_SHIFT;
2723 : 0 : pipe->wrr_tokens[2] =
2724 : 0 : (grinder->wrr_tokens[2] & grinder->wrr_mask[2]) >>
2725 : : RTE_SCHED_WRR_SHIFT;
2726 : 0 : pipe->wrr_tokens[3] =
2727 : 0 : (grinder->wrr_tokens[3] & grinder->wrr_mask[3]) >>
2728 : : RTE_SCHED_WRR_SHIFT;
2729 : 0 : }
2730 : :
2731 : : static inline void
2732 : 0 : grinder_wrr(struct rte_sched_subport *subport, uint32_t pos)
2733 : : {
2734 : 0 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2735 : : uint16_t wrr_tokens_min;
2736 : :
2737 : 0 : grinder->wrr_tokens[0] |= ~grinder->wrr_mask[0];
2738 : 0 : grinder->wrr_tokens[1] |= ~grinder->wrr_mask[1];
2739 : 0 : grinder->wrr_tokens[2] |= ~grinder->wrr_mask[2];
2740 : 0 : grinder->wrr_tokens[3] |= ~grinder->wrr_mask[3];
2741 : :
2742 [ # # ]: 0 : grinder->qpos = rte_min_pos_4_u16(grinder->wrr_tokens);
2743 : 0 : wrr_tokens_min = grinder->wrr_tokens[grinder->qpos];
2744 : :
2745 : 0 : grinder->wrr_tokens[0] -= wrr_tokens_min;
2746 : 0 : grinder->wrr_tokens[1] -= wrr_tokens_min;
2747 : 0 : grinder->wrr_tokens[2] -= wrr_tokens_min;
2748 : 0 : grinder->wrr_tokens[3] -= wrr_tokens_min;
2749 : 0 : }
2750 : :
2751 : :
2752 : : #define grinder_evict(subport, pos)
2753 : :
2754 : : static inline void
2755 : : grinder_prefetch_pipe(struct rte_sched_subport *subport, uint32_t pos)
2756 : : {
2757 : : struct rte_sched_grinder *grinder = subport->grinder + pos;
2758 : :
2759 : 1 : rte_prefetch0(grinder->pipe);
2760 : 1 : rte_prefetch0(grinder->queue[0]);
2761 : : }
2762 : :
2763 : : static inline void
2764 : 1 : grinder_prefetch_tc_queue_arrays(struct rte_sched_subport *subport, uint32_t pos)
2765 : : {
2766 : 1 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2767 : : uint16_t qsize, qr[RTE_SCHED_MAX_QUEUES_PER_TC];
2768 : :
2769 : 1 : qsize = grinder->qsize;
2770 : 1 : grinder->qpos = 0;
2771 : :
2772 [ + - ]: 1 : if (grinder->tc_index < RTE_SCHED_TRAFFIC_CLASS_BE) {
2773 : 1 : qr[0] = grinder->queue[0]->qr & (qsize - 1);
2774 : :
2775 : 1 : rte_prefetch0(grinder->qbase[0] + qr[0]);
2776 : : return;
2777 : : }
2778 : :
2779 : 0 : qr[0] = grinder->queue[0]->qr & (qsize - 1);
2780 : 0 : qr[1] = grinder->queue[1]->qr & (qsize - 1);
2781 : 0 : qr[2] = grinder->queue[2]->qr & (qsize - 1);
2782 : 0 : qr[3] = grinder->queue[3]->qr & (qsize - 1);
2783 : :
2784 : 0 : rte_prefetch0(grinder->qbase[0] + qr[0]);
2785 : 0 : rte_prefetch0(grinder->qbase[1] + qr[1]);
2786 : :
2787 : 0 : grinder_wrr_load(subport, pos);
2788 : 0 : grinder_wrr(subport, pos);
2789 : :
2790 : 0 : rte_prefetch0(grinder->qbase[2] + qr[2]);
2791 : 0 : rte_prefetch0(grinder->qbase[3] + qr[3]);
2792 : : }
2793 : :
2794 : : static inline void
2795 : 10 : grinder_prefetch_mbuf(struct rte_sched_subport *subport, uint32_t pos)
2796 : : {
2797 : 10 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2798 : 10 : uint32_t qpos = grinder->qpos;
2799 : 10 : struct rte_mbuf **qbase = grinder->qbase[qpos];
2800 : 10 : uint16_t qsize = grinder->qsize;
2801 : 10 : uint16_t qr = grinder->queue[qpos]->qr & (qsize - 1);
2802 : :
2803 : 10 : grinder->pkt = qbase[qr];
2804 : : rte_prefetch0(grinder->pkt);
2805 : :
2806 [ + + ]: 10 : if (unlikely((qr & 0x7) == 7)) {
2807 : 1 : uint16_t qr_next = (grinder->queue[qpos]->qr + 1) & (qsize - 1);
2808 : :
2809 : 1 : rte_prefetch0(qbase + qr_next);
2810 : : }
2811 : 10 : }
2812 : :
2813 : : static inline uint32_t
2814 : 97 : grinder_handle(struct rte_sched_port *port,
2815 : : struct rte_sched_subport *subport, uint32_t pos)
2816 : : {
2817 : 97 : struct rte_sched_grinder *grinder = subport->grinder + pos;
2818 : :
2819 [ + + + + : 97 : switch (grinder->state) {
- ]
2820 : 85 : case e_GRINDER_PREFETCH_PIPE:
2821 : : {
2822 [ + + ]: 85 : if (grinder_next_pipe(port, subport, pos)) {
2823 : : grinder_prefetch_pipe(subport, pos);
2824 : 1 : subport->busy_grinders++;
2825 : :
2826 : 1 : grinder->state = e_GRINDER_PREFETCH_TC_QUEUE_ARRAYS;
2827 : 1 : return 0;
2828 : : }
2829 : :
2830 : : return 0;
2831 : : }
2832 : :
2833 : 1 : case e_GRINDER_PREFETCH_TC_QUEUE_ARRAYS:
2834 : : {
2835 : 1 : struct rte_sched_pipe *pipe = grinder->pipe;
2836 : :
2837 : 1 : grinder->pipe_params = subport->pipe_profiles + pipe->profile;
2838 : 1 : grinder->subport_params = port->subport_profiles +
2839 : 1 : subport->profile;
2840 : :
2841 : 1 : grinder_prefetch_tc_queue_arrays(subport, pos);
2842 : :
2843 [ + - ]: 1 : if (subport->tc_ov_enabled)
2844 : 1 : grinder_credits_update_with_tc_ov(port, subport, pos);
2845 : : else
2846 : 0 : grinder_credits_update(port, subport, pos);
2847 : :
2848 : 1 : grinder->state = e_GRINDER_PREFETCH_MBUF;
2849 : 1 : return 0;
2850 : : }
2851 : :
2852 : 1 : case e_GRINDER_PREFETCH_MBUF:
2853 : : {
2854 : 1 : grinder_prefetch_mbuf(subport, pos);
2855 : :
2856 : 1 : grinder->state = e_GRINDER_READ_MBUF;
2857 : 1 : return 0;
2858 : : }
2859 : :
2860 : 10 : case e_GRINDER_READ_MBUF:
2861 : : {
2862 : : uint32_t wrr_active, result = 0;
2863 : :
2864 : 10 : result = grinder_schedule(port, subport, pos);
2865 : :
2866 : 10 : wrr_active = (grinder->tc_index == RTE_SCHED_TRAFFIC_CLASS_BE);
2867 : :
2868 : : /* Look for next packet within the same TC */
2869 [ + - + + ]: 10 : if (result && grinder->qmask) {
2870 [ - + ]: 9 : if (wrr_active)
2871 : 0 : grinder_wrr(subport, pos);
2872 : :
2873 : 9 : grinder_prefetch_mbuf(subport, pos);
2874 : :
2875 : 9 : return 1;
2876 : : }
2877 : :
2878 [ - + ]: 1 : if (wrr_active)
2879 : 0 : grinder_wrr_store(subport, pos);
2880 : :
2881 : : /* Look for another active TC within same pipe */
2882 [ - + ]: 1 : if (grinder_next_tc(port, subport, pos)) {
2883 : 0 : grinder_prefetch_tc_queue_arrays(subport, pos);
2884 : :
2885 : 0 : grinder->state = e_GRINDER_PREFETCH_MBUF;
2886 : 0 : return result;
2887 : : }
2888 : :
2889 [ - + ]: 1 : if (grinder->productive == 0 &&
2890 [ # # ]: 0 : subport->pipe_loop == RTE_SCHED_PIPE_INVALID)
2891 : 0 : subport->pipe_loop = grinder->pindex;
2892 : :
2893 : : grinder_evict(subport, pos);
2894 : :
2895 : : /* Look for another active pipe */
2896 [ - + ]: 1 : if (grinder_next_pipe(port, subport, pos)) {
2897 : : grinder_prefetch_pipe(subport, pos);
2898 : :
2899 : 0 : grinder->state = e_GRINDER_PREFETCH_TC_QUEUE_ARRAYS;
2900 : 0 : return result;
2901 : : }
2902 : :
2903 : : /* No active pipe found */
2904 : 1 : subport->busy_grinders--;
2905 : :
2906 : 1 : grinder->state = e_GRINDER_PREFETCH_PIPE;
2907 : 1 : return result;
2908 : : }
2909 : :
2910 : 0 : default:
2911 : 0 : rte_panic("Algorithmic error (invalid state)\n");
2912 : : return 0;
2913 : : }
2914 : : }
2915 : :
2916 : : static inline void
2917 : 1 : rte_sched_port_time_resync(struct rte_sched_port *port)
2918 : : {
2919 : : uint64_t cycles = rte_get_tsc_cycles();
2920 : : uint64_t cycles_diff;
2921 : : uint64_t bytes_diff;
2922 : : uint32_t i;
2923 : :
2924 [ - + ]: 1 : if (cycles < port->time_cpu_cycles)
2925 : 0 : port->time_cpu_cycles = 0;
2926 : :
2927 : 1 : cycles_diff = cycles - port->time_cpu_cycles;
2928 : : /* Compute elapsed time in bytes */
2929 [ + - ]: 1 : bytes_diff = rte_reciprocal_divide(cycles_diff << RTE_SCHED_TIME_SHIFT,
2930 : : port->inv_cycles_per_byte);
2931 : :
2932 : : /* Advance port time */
2933 : 1 : port->time_cpu_cycles +=
2934 : 1 : (bytes_diff * port->cycles_per_byte) >> RTE_SCHED_TIME_SHIFT;
2935 : 1 : port->time_cpu_bytes += bytes_diff;
2936 [ + - ]: 1 : if (port->time < port->time_cpu_bytes)
2937 : 1 : port->time = port->time_cpu_bytes;
2938 : :
2939 : : /* Reset pipe loop detection */
2940 [ + + ]: 2 : for (i = 0; i < port->n_subports_per_port; i++)
2941 : 1 : port->subports[i]->pipe_loop = RTE_SCHED_PIPE_INVALID;
2942 : 1 : }
2943 : :
2944 : : static inline int
2945 : : rte_sched_port_exceptions(struct rte_sched_subport *subport, int second_pass)
2946 : : {
2947 : : int exceptions;
2948 : :
2949 : : /* Check if any exception flag is set */
2950 [ + + - + ]: 96 : exceptions = (second_pass && subport->busy_grinders == 0) ||
2951 [ + - ]: 96 : (subport->pipe_exhaustion == 1);
2952 : :
2953 : : /* Clear exception flags */
2954 : 96 : subport->pipe_exhaustion = 0;
2955 : :
2956 : : return exceptions;
2957 : : }
2958 : :
2959 : : int
2960 : 1 : rte_sched_port_dequeue(struct rte_sched_port *port, struct rte_mbuf **pkts, uint32_t n_pkts)
2961 : : {
2962 : : struct rte_sched_subport *subport;
2963 : 1 : uint32_t subport_id = port->subport_id;
2964 : : uint32_t i, n_subports = 0, count;
2965 : :
2966 : 1 : port->pkts_out = pkts;
2967 : 1 : port->n_pkts_out = 0;
2968 : :
2969 : 1 : rte_sched_port_time_resync(port);
2970 : :
2971 : : /* Take each queue in the grinder one step further */
2972 : 96 : for (i = 0, count = 0; ; i++) {
2973 : 97 : subport = port->subports[subport_id];
2974 : :
2975 : 97 : count += grinder_handle(port, subport,
2976 : : i & (RTE_SCHED_PORT_N_GRINDERS - 1));
2977 : :
2978 [ + + ]: 97 : if (count == n_pkts) {
2979 : 1 : subport_id++;
2980 : :
2981 [ + - ]: 1 : if (subport_id == port->n_subports_per_port)
2982 : : subport_id = 0;
2983 : :
2984 : 1 : port->subport_id = subport_id;
2985 : 1 : break;
2986 : : }
2987 : :
2988 : : if (rte_sched_port_exceptions(subport, i >= RTE_SCHED_PORT_N_GRINDERS)) {
2989 : : i = 0;
2990 : 0 : subport_id++;
2991 : 0 : n_subports++;
2992 : : }
2993 : :
2994 [ - + ]: 96 : if (subport_id == port->n_subports_per_port)
2995 : : subport_id = 0;
2996 : :
2997 [ - + ]: 96 : if (n_subports == port->n_subports_per_port) {
2998 : 0 : port->subport_id = subport_id;
2999 : 0 : break;
3000 : : }
3001 : : }
3002 : :
3003 : 1 : return count;
3004 : : }
3005 : :
3006 [ - + ]: 235 : RTE_LOG_REGISTER_DEFAULT(sched_logtype, INFO);
|