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