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