8530caf9099bf61c9dad8f83a951a12d4925f941
[dpdk.git] / lib / librte_sched / rte_sched.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  * 
7  *   Redistribution and use in source and binary forms, with or without 
8  *   modification, are permitted provided that the following conditions 
9  *   are met:
10  * 
11  *     * Redistributions of source code must retain the above copyright 
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright 
14  *       notice, this list of conditions and the following disclaimer in 
15  *       the documentation and/or other materials provided with the 
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its 
18  *       contributors may be used to endorse or promote products derived 
19  *       from this software without specific prior written permission.
20  * 
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  * 
33  */
34
35 #include <stdio.h>
36 #include <string.h>
37
38 #include <rte_common.h>
39 #include <rte_log.h>
40 #include <rte_memory.h>
41 #include <rte_memzone.h>
42 #include <rte_cycles.h>
43 #include <rte_prefetch.h>
44 #include <rte_branch_prediction.h>
45 #include <rte_mbuf.h>
46
47 #include "rte_sched.h"
48 #include "rte_bitmap.h"
49 #include "rte_sched_common.h"
50 #include "rte_approx.h"
51
52 #ifdef __INTEL_COMPILER
53 #pragma warning(disable:2259) /* conversion may lose significant bits */
54 #endif
55
56 #ifndef RTE_SCHED_DEBUG
57 #define RTE_SCHED_DEBUG                       0
58 #endif
59
60 #ifndef RTE_SCHED_OPTIMIZATIONS
61 #define RTE_SCHED_OPTIMIZATIONS                   0
62 #endif
63
64 #if RTE_SCHED_OPTIMIZATIONS
65 #include <immintrin.h>
66 #endif
67
68 #define RTE_SCHED_ENQUEUE                     1
69
70 #define RTE_SCHED_TS                          1
71
72 #if RTE_SCHED_TS == 0 /* Infinite credits. Traffic shaping disabled. */
73 #define RTE_SCHED_TS_CREDITS_UPDATE           0
74 #define RTE_SCHED_TS_CREDITS_CHECK            0
75 #else                 /* Real Credits. Full traffic shaping implemented. */
76 #define RTE_SCHED_TS_CREDITS_UPDATE           1
77 #define RTE_SCHED_TS_CREDITS_CHECK            1
78 #endif
79
80 #ifndef RTE_SCHED_TB_RATE_CONFIG_ERR
81 #define RTE_SCHED_TB_RATE_CONFIG_ERR          (1e-7)
82 #endif
83
84 #define RTE_SCHED_WRR                         1
85
86 #ifndef RTE_SCHED_WRR_SHIFT
87 #define RTE_SCHED_WRR_SHIFT                   3
88 #endif
89
90 #ifndef RTE_SCHED_PORT_N_GRINDERS
91 #define RTE_SCHED_PORT_N_GRINDERS             8
92 #endif
93 #if (RTE_SCHED_PORT_N_GRINDERS == 0) || (RTE_SCHED_PORT_N_GRINDERS & (RTE_SCHED_PORT_N_GRINDERS - 1))
94 #error Number of grinders must be non-zero and a power of 2
95 #endif
96 #if (RTE_SCHED_OPTIMIZATIONS && (RTE_SCHED_PORT_N_GRINDERS != 8))
97 #error Number of grinders must be 8 when RTE_SCHED_OPTIMIZATIONS is set
98 #endif
99
100 #define RTE_SCHED_GRINDER_PCACHE_SIZE         (64 / RTE_SCHED_QUEUES_PER_PIPE)
101         
102 #define RTE_SCHED_PIPE_INVALID                UINT32_MAX
103
104 #define RTE_SCHED_BMP_POS_INVALID             UINT32_MAX
105
106 struct rte_sched_subport {
107         /* Token bucket (TB) */
108         uint64_t tb_time; /* time of last update */
109         uint32_t tb_period;
110         uint32_t tb_credits_per_period;
111         uint32_t tb_size;
112         uint32_t tb_credits;
113
114         /* Traffic classes (TCs) */
115         uint64_t tc_time; /* time of next update */
116         uint32_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
117         uint32_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
118         uint32_t tc_period;
119         
120         /* TC oversubscription */
121         uint32_t tc_ov_wm;
122         uint32_t tc_ov_wm_min;
123         uint32_t tc_ov_wm_max;
124         uint8_t tc_ov_period_id;
125         uint8_t tc_ov;
126         uint32_t tc_ov_n;
127         double tc_ov_rate;
128         
129         /* Statistics */
130         struct rte_sched_subport_stats stats;
131 };
132
133 struct rte_sched_pipe_profile {
134         /* Token bucket (TB) */
135         uint32_t tb_period;
136         uint32_t tb_credits_per_period;
137         uint32_t tb_size;
138         
139         /* Pipe traffic classes */
140         uint32_t tc_period;
141         uint32_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
142         uint8_t tc_ov_weight;
143         
144         /* Pipe queues */
145         uint8_t  wrr_cost[RTE_SCHED_QUEUES_PER_PIPE];
146 };
147
148 struct rte_sched_pipe {
149         /* Token bucket (TB) */
150         uint64_t tb_time; /* time of last update */
151         uint32_t tb_credits;
152
153         /* Pipe profile and flags */
154         uint32_t profile;
155         
156         /* Traffic classes (TCs) */
157         uint64_t tc_time; /* time of next update */
158         uint32_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
159         
160         /* Weighted Round Robin (WRR) */
161         uint8_t wrr_tokens[RTE_SCHED_QUEUES_PER_PIPE];
162         
163         /* TC oversubscription */
164         uint32_t tc_ov_credits;
165         uint8_t tc_ov_period_id;
166         uint8_t reserved[3];
167 } __rte_cache_aligned;
168
169 struct rte_sched_queue {
170         uint16_t qw;
171         uint16_t qr;
172 };
173
174 struct rte_sched_queue_extra {
175         struct rte_sched_queue_stats stats;
176 #ifdef RTE_SCHED_RED
177         struct rte_red red;
178 #endif
179 };
180
181 enum grinder_state {
182         e_GRINDER_PREFETCH_PIPE = 0,
183         e_GRINDER_PREFETCH_TC_QUEUE_ARRAYS,
184         e_GRINDER_PREFETCH_MBUF,
185         e_GRINDER_READ_MBUF
186 };
187
188 struct rte_sched_grinder {
189         /* Pipe cache */
190         uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
191         uint32_t pcache_qindex[RTE_SCHED_GRINDER_PCACHE_SIZE];
192         uint32_t pcache_w;
193         uint32_t pcache_r;
194         
195         /* Current pipe */
196         enum grinder_state state;
197         uint32_t productive;
198         uint32_t pindex;
199         struct rte_sched_subport *subport;
200         struct rte_sched_pipe *pipe;
201         struct rte_sched_pipe_profile *pipe_params;
202
203         /* TC cache */
204         uint8_t tccache_qmask[4];
205         uint32_t tccache_qindex[4];
206         uint32_t tccache_w;
207         uint32_t tccache_r;
208         
209         /* Current TC */
210         uint32_t tc_index;
211         struct rte_sched_queue *queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
212         struct rte_mbuf **qbase[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
213         uint32_t qindex[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
214         uint16_t qsize;
215         uint32_t qmask;
216         uint32_t qpos;
217         struct rte_mbuf *pkt;
218         
219         /* WRR */
220         uint16_t wrr_tokens[RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS];
221         uint16_t wrr_mask[RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS];
222         uint8_t wrr_cost[RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS];
223 };
224
225 struct rte_sched_port {
226         /* User parameters */
227         uint32_t n_subports_per_port;
228         uint32_t n_pipes_per_subport;
229         uint32_t rate;
230         uint32_t mtu;
231         uint32_t frame_overhead;
232         uint16_t qsize[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
233         uint32_t n_pipe_profiles;
234         uint32_t pipe_tc3_rate_max;
235 #ifdef RTE_SCHED_RED
236         struct rte_red_config red_config[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE][e_RTE_METER_COLORS];
237 #endif
238
239         /* Timing */
240         uint64_t time_cpu_cycles;     /* Current CPU time measured in CPU cyles */
241         uint64_t time_cpu_bytes;      /* Current CPU time measured in bytes */
242         uint64_t time;                /* Current NIC TX time measured in bytes */
243         double cycles_per_byte;       /* CPU cycles per byte */
244         
245         /* Scheduling loop detection */
246         uint32_t pipe_loop;
247         uint32_t pipe_exhaustion;
248
249         /* Bitmap */
250         struct rte_bitmap *bmp;
251         uint32_t grinder_base_bmp_pos[RTE_SCHED_PORT_N_GRINDERS] __rte_aligned_16;
252         
253         /* Grinders */
254         struct rte_sched_grinder grinder[RTE_SCHED_PORT_N_GRINDERS];
255         uint32_t busy_grinders;
256         struct rte_mbuf **pkts_out;
257         uint32_t n_pkts_out;
258         
259         /* Queue base calculation */
260         uint32_t qsize_add[RTE_SCHED_QUEUES_PER_PIPE];
261         uint32_t qsize_sum;
262         
263         /* Large data structures */
264         struct rte_sched_subport *subport;
265         struct rte_sched_pipe *pipe;
266         struct rte_sched_queue *queue;
267         struct rte_sched_queue_extra *queue_extra;
268         struct rte_sched_pipe_profile *pipe_profiles;
269         uint8_t *bmp_array;
270         struct rte_mbuf **queue_array;
271         uint8_t memory[0] __rte_cache_aligned;
272 } __rte_cache_aligned;
273
274 enum rte_sched_port_array {
275         e_RTE_SCHED_PORT_ARRAY_SUBPORT = 0,
276         e_RTE_SCHED_PORT_ARRAY_PIPE,
277         e_RTE_SCHED_PORT_ARRAY_QUEUE,
278         e_RTE_SCHED_PORT_ARRAY_QUEUE_EXTRA,
279         e_RTE_SCHED_PORT_ARRAY_PIPE_PROFILES,
280         e_RTE_SCHED_PORT_ARRAY_BMP_ARRAY,
281         e_RTE_SCHED_PORT_ARRAY_QUEUE_ARRAY,
282         e_RTE_SCHED_PORT_ARRAY_TOTAL,
283 };
284
285 #ifdef RTE_SCHED_COLLECT_STATS
286
287 static inline uint32_t
288 rte_sched_port_queues_per_subport(struct rte_sched_port *port)
289 {
290         return RTE_SCHED_QUEUES_PER_PIPE * port->n_pipes_per_subport;
291 }
292
293 #endif
294
295 static inline uint32_t
296 rte_sched_port_queues_per_port(struct rte_sched_port *port)
297 {
298         return RTE_SCHED_QUEUES_PER_PIPE * port->n_pipes_per_subport * port->n_subports_per_port;
299 }
300
301 static int
302 rte_sched_port_check_params(struct rte_sched_port_params *params)
303 {
304         uint32_t i, j;
305         
306         if (params == NULL) {
307                 return -1;
308         }
309         
310         /* name */
311         if (params->name == NULL) {
312                 return -2;
313         }
314         
315         /* socket */
316         if ((params->socket < 0) || (params->socket >= RTE_MAX_NUMA_NODES)) {
317                 return -3;
318         }
319         
320         /* rate */
321         if (params->rate == 0) {
322                 return -4;
323         }
324         
325         /* mtu */
326         if (params->mtu == 0) {
327                 return -5;
328         }
329         
330         /* n_subports_per_port: non-zero, power of 2 */
331         if ((params->n_subports_per_port == 0) || (!rte_is_power_of_2(params->n_subports_per_port))) {
332                 return -6;
333         }
334
335         /* n_pipes_per_subport: non-zero, power of 2 */
336         if ((params->n_pipes_per_subport == 0) || (!rte_is_power_of_2(params->n_pipes_per_subport))) {
337                 return -7;
338         }
339         
340         /* qsize: non-zero, power of 2, no bigger than 32K (due to 16-bit read/write pointers) */
341         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i ++) {
342                 uint16_t qsize = params->qsize[i];
343                 
344                 if ((qsize == 0) || (!rte_is_power_of_2(qsize))) {
345                         return -8;
346                 }
347         }
348         
349         /* pipe_profiles and n_pipe_profiles */
350         if ((params->pipe_profiles == NULL) || 
351             (params->n_pipe_profiles == 0) ||
352             (params->n_pipe_profiles > RTE_SCHED_PIPE_PROFILES_PER_PORT)) {
353                 return -9;
354         }
355         
356         for (i = 0; i < params->n_pipe_profiles; i ++) {
357                 struct rte_sched_pipe_params *p = params->pipe_profiles + i;
358                 
359                 /* TB rate: non-zero, not greater than port rate */
360                 if ((p->tb_rate == 0) || (p->tb_rate > params->rate)) {
361                         return -10;
362                 }
363                 
364                 /* TB size: non-zero */
365                 if (p->tb_size == 0) {
366                         return -11;
367                 }
368
369                 /* TC rate: non-zero, less than pipe rate */
370                 for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j ++) {
371                         if ((p->tc_rate[j] == 0) || (p->tc_rate[j] > p->tb_rate)) {
372                                 return -12;
373                         }
374                 }
375                 
376                 /* TC period: non-zero */
377                 if (p->tc_period == 0) {
378                         return -13;
379                 }
380
381 #ifdef RTE_SCHED_SUBPORT_TC_OV
382                 /* TC3 oversubscription weight: non-zero */
383                 if (p->tc_ov_weight == 0) {
384                         return -14;
385                 }
386 #endif
387
388                 /* Queue WRR weights: non-zero */
389                 for (j = 0; j < RTE_SCHED_QUEUES_PER_PIPE; j ++) {
390                         if (p->wrr_weights[j] == 0) {
391                                 return -15;
392                         }
393                 }
394         }
395         
396         return 0;
397 }
398
399 static uint32_t
400 rte_sched_port_get_array_base(struct rte_sched_port_params *params, enum rte_sched_port_array array)
401 {
402         uint32_t n_subports_per_port = params->n_subports_per_port;
403         uint32_t n_pipes_per_subport = params->n_pipes_per_subport;
404         uint32_t n_pipes_per_port = n_pipes_per_subport * n_subports_per_port;
405         uint32_t n_queues_per_port = RTE_SCHED_QUEUES_PER_PIPE * n_pipes_per_subport * n_subports_per_port;
406         
407         uint32_t size_subport = n_subports_per_port * sizeof(struct rte_sched_subport);
408         uint32_t size_pipe = n_pipes_per_port * sizeof(struct rte_sched_pipe);
409         uint32_t size_queue = n_queues_per_port * sizeof(struct rte_sched_queue);
410         uint32_t size_queue_extra = n_queues_per_port * sizeof(struct rte_sched_queue_extra);
411         uint32_t size_pipe_profiles = RTE_SCHED_PIPE_PROFILES_PER_PORT * sizeof(struct rte_sched_pipe_profile);
412         uint32_t size_bmp_array = rte_bitmap_get_memory_footprint(n_queues_per_port);
413         uint32_t size_per_pipe_queue_array, size_queue_array;
414         
415         uint32_t base, i;
416         
417         size_per_pipe_queue_array = 0;
418         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i ++) {
419                 size_per_pipe_queue_array += RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS * params->qsize[i] * sizeof(struct rte_mbuf *);
420         }
421         size_queue_array = n_pipes_per_port * size_per_pipe_queue_array;
422         
423         base = 0;
424         
425         if (array == e_RTE_SCHED_PORT_ARRAY_SUBPORT) return base;
426         base += CACHE_LINE_ROUNDUP(size_subport);
427         
428         if (array == e_RTE_SCHED_PORT_ARRAY_PIPE) return base;
429         base += CACHE_LINE_ROUNDUP(size_pipe);
430
431         if (array == e_RTE_SCHED_PORT_ARRAY_QUEUE) return base;
432         base += CACHE_LINE_ROUNDUP(size_queue);
433         
434         if (array == e_RTE_SCHED_PORT_ARRAY_QUEUE_EXTRA) return base;
435         base += CACHE_LINE_ROUNDUP(size_queue_extra);
436         
437         if (array == e_RTE_SCHED_PORT_ARRAY_PIPE_PROFILES) return base;
438         base += CACHE_LINE_ROUNDUP(size_pipe_profiles);
439
440         if (array == e_RTE_SCHED_PORT_ARRAY_BMP_ARRAY) return base;
441         base += CACHE_LINE_ROUNDUP(size_bmp_array);
442
443         if (array == e_RTE_SCHED_PORT_ARRAY_QUEUE_ARRAY) return base;
444         base += CACHE_LINE_ROUNDUP(size_queue_array);
445
446         return base;
447 }
448
449 uint32_t
450 rte_sched_port_get_memory_footprint(struct rte_sched_port_params *params)
451 {
452         uint32_t size0, size1;
453         int status;
454         
455         status = rte_sched_port_check_params(params);
456         if (status != 0) {
457                 RTE_LOG(INFO, SCHED, "Port scheduler params check failed (%d)\n", status);
458                 
459                 return 0;
460         }
461         
462         size0 = sizeof(struct rte_sched_port);
463         size1 = rte_sched_port_get_array_base(params, e_RTE_SCHED_PORT_ARRAY_TOTAL);
464         
465         return (size0 + size1);
466 }
467
468 static void
469 rte_sched_port_config_qsize(struct rte_sched_port *port)
470 {
471         /* TC 0 */
472         port->qsize_add[0] = 0;
473         port->qsize_add[1] = port->qsize_add[0] + port->qsize[0];
474         port->qsize_add[2] = port->qsize_add[1] + port->qsize[0];
475         port->qsize_add[3] = port->qsize_add[2] + port->qsize[0];
476         
477         /* TC 1 */
478         port->qsize_add[4] = port->qsize_add[3] + port->qsize[0];
479         port->qsize_add[5] = port->qsize_add[4] + port->qsize[1];
480         port->qsize_add[6] = port->qsize_add[5] + port->qsize[1];
481         port->qsize_add[7] = port->qsize_add[6] + port->qsize[1];
482
483         /* TC 2 */
484         port->qsize_add[8] = port->qsize_add[7] + port->qsize[1];
485         port->qsize_add[9] = port->qsize_add[8] + port->qsize[2];
486         port->qsize_add[10] = port->qsize_add[9] + port->qsize[2];
487         port->qsize_add[11] = port->qsize_add[10] + port->qsize[2];
488
489         /* TC 3 */
490         port->qsize_add[12] = port->qsize_add[11] + port->qsize[2];
491         port->qsize_add[13] = port->qsize_add[12] + port->qsize[3];
492         port->qsize_add[14] = port->qsize_add[13] + port->qsize[3];
493         port->qsize_add[15] = port->qsize_add[14] + port->qsize[3];
494         
495         port->qsize_sum = port->qsize_add[15] + port->qsize[3];
496 }
497
498 static void 
499 rte_sched_port_log_pipe_profile(struct rte_sched_port *port, uint32_t i)
500 {
501         struct rte_sched_pipe_profile *p = port->pipe_profiles + i;
502         
503         RTE_LOG(INFO, SCHED, "Low level config for pipe profile %u:\n"
504                 "\tToken bucket: period = %u, credits per period = %u, size = %u\n"
505                 "\tTraffic classes: period = %u, credits per period = [%u, %u, %u, %u]\n"
506                 "\tTraffic class 3 oversubscription: weight = %hhu\n"
507                 "\tWRR cost: [%hhu, %hhu, %hhu, %hhu], [%hhu, %hhu, %hhu, %hhu], [%hhu, %hhu, %hhu, %hhu], [%hhu, %hhu, %hhu, %hhu]\n",
508                 i,
509                 
510                 /* Token bucket */
511                 p->tb_period,
512                 p->tb_credits_per_period,
513                 p->tb_size,
514                 
515                 /* Traffic classes */
516                 p->tc_period,
517                 p->tc_credits_per_period[0],
518                 p->tc_credits_per_period[1],
519                 p->tc_credits_per_period[2],
520                 p->tc_credits_per_period[3],
521                 
522                 /* Traffic class 3 oversubscription */
523                 p->tc_ov_weight,
524                 
525                 /* WRR */
526                 p->wrr_cost[ 0], p->wrr_cost[ 1], p->wrr_cost[ 2], p->wrr_cost[ 3],
527                 p->wrr_cost[ 4], p->wrr_cost[ 5], p->wrr_cost[ 6], p->wrr_cost[ 7],
528                 p->wrr_cost[ 8], p->wrr_cost[ 9], p->wrr_cost[10], p->wrr_cost[11],
529                 p->wrr_cost[12], p->wrr_cost[13], p->wrr_cost[14], p->wrr_cost[15]);
530 }
531
532 static inline uint64_t
533 rte_sched_time_ms_to_bytes(uint32_t time_ms, uint32_t rate)
534 {
535         uint64_t time = time_ms;
536         time = (time * rate) / 1000;
537         
538         return time;
539 }
540
541 static void
542 rte_sched_port_config_pipe_profile_table(struct rte_sched_port *port, struct rte_sched_port_params *params)
543 {
544         uint32_t i, j;
545         
546         for (i = 0; i < port->n_pipe_profiles; i ++) {
547                 struct rte_sched_pipe_params *src = params->pipe_profiles + i;
548                 struct rte_sched_pipe_profile *dst = port->pipe_profiles + i;
549                 
550                 /* Token Bucket */
551                 if (src->tb_rate == params->rate) {
552                         dst->tb_credits_per_period = 1;
553                         dst->tb_period = 1;
554                 } else {
555                         double tb_rate = ((double) src->tb_rate) / ((double) params->rate);
556                         double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
557                         
558                         rte_approx(tb_rate, d, &dst->tb_credits_per_period, &dst->tb_period);
559                 }
560                 dst->tb_size = src->tb_size;
561                 
562                 /* Traffic Classes */
563                 dst->tc_period = (uint32_t) rte_sched_time_ms_to_bytes(src->tc_period, params->rate);
564                 for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j ++) {
565                         dst->tc_credits_per_period[j] = (uint32_t) rte_sched_time_ms_to_bytes(src->tc_period, src->tc_rate[j]);
566                 }
567 #ifdef RTE_SCHED_SUBPORT_TC_OV
568                 dst->tc_ov_weight = src->tc_ov_weight;
569 #endif
570                 
571                 /* WRR */
572                 for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j ++) {
573                         uint32_t wrr_cost[RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS];
574                         uint32_t lcd, lcd1, lcd2;
575                         uint32_t qindex;
576                         
577                         qindex = j * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS;
578                         
579                         wrr_cost[0] = src->wrr_weights[qindex];
580                         wrr_cost[1] = src->wrr_weights[qindex + 1];
581                         wrr_cost[2] = src->wrr_weights[qindex + 2];
582                         wrr_cost[3] = src->wrr_weights[qindex + 3];
583                         
584                         lcd1 = rte_get_lcd(wrr_cost[0], wrr_cost[1]);
585                         lcd2 = rte_get_lcd(wrr_cost[2], wrr_cost[3]);
586                         lcd = rte_get_lcd(lcd1, lcd2);
587
588                         wrr_cost[0] = lcd / wrr_cost[0];
589                         wrr_cost[1] = lcd / wrr_cost[1];
590                         wrr_cost[2] = lcd / wrr_cost[2];
591                         wrr_cost[3] = lcd / wrr_cost[3];
592                         
593                         dst->wrr_cost[qindex] = (uint8_t) wrr_cost[0];
594                         dst->wrr_cost[qindex + 1] = (uint8_t) wrr_cost[1];
595                         dst->wrr_cost[qindex + 2] = (uint8_t) wrr_cost[2];
596                         dst->wrr_cost[qindex + 3] = (uint8_t) wrr_cost[3];
597                 }
598         
599                 rte_sched_port_log_pipe_profile(port, i);
600         }
601
602         port->pipe_tc3_rate_max = 0;
603         for (i = 0; i < port->n_pipe_profiles; i ++) {
604                 struct rte_sched_pipe_params *src = params->pipe_profiles + i;
605                 uint32_t pipe_tc3_rate = src->tc_rate[3];
606                 
607                 if (port->pipe_tc3_rate_max < pipe_tc3_rate) {
608                         port->pipe_tc3_rate_max = pipe_tc3_rate;
609                 }
610         }
611 }
612
613 struct rte_sched_port *
614 rte_sched_port_config(struct rte_sched_port_params *params)
615 {
616         struct rte_sched_port *port = NULL;
617         const struct rte_memzone *mz = NULL;
618         uint32_t mem_size, bmp_mem_size, n_queues_per_port, i;
619         
620         /* Check user parameters. Determine the amount of memory to allocate */
621         mem_size = rte_sched_port_get_memory_footprint(params);
622         if (mem_size == 0) {
623                 return NULL;
624         }
625         
626         /* Allocate memory to store the data structures */
627         mz = rte_memzone_lookup(params->name);
628         if (mz) {
629                 /* Use existing memzone, provided that its size is big enough */
630                 if (mz->len < mem_size) {
631                         return NULL;
632                 }
633         } else {
634                 /* Create new memzone */
635                 mz = rte_memzone_reserve(params->name, mem_size, params->socket, 0);            
636                 if (mz == NULL) {
637                         return NULL;
638                 }
639         }
640         memset(mz->addr, 0, mem_size);
641         port = (struct rte_sched_port *) mz->addr;
642
643         /* User parameters */
644         port->n_subports_per_port = params->n_subports_per_port;
645         port->n_pipes_per_subport = params->n_pipes_per_subport;
646         port->rate = params->rate;
647         port->mtu = params->mtu + params->frame_overhead;
648         port->frame_overhead = params->frame_overhead;
649         memcpy(port->qsize, params->qsize, sizeof(params->qsize));
650         port->n_pipe_profiles = params->n_pipe_profiles;
651
652 #ifdef RTE_SCHED_RED
653         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
654                 uint32_t j;
655                 
656                 for (j = 0; j < e_RTE_METER_COLORS; j++) {
657                         if (rte_red_config_init(&port->red_config[i][j],
658                                 params->red_params[i][j].wq_log2,
659                                 params->red_params[i][j].min_th,
660                                 params->red_params[i][j].max_th,
661                                 params->red_params[i][j].maxp_inv) != 0) {
662                                 return NULL;
663                         }
664                 }
665         }
666 #endif
667
668         /* Timing */
669         port->time_cpu_cycles = rte_get_tsc_cycles();
670         port->time_cpu_bytes = 0;
671         port->time = 0;
672         port->cycles_per_byte = ((double) rte_get_tsc_hz()) / ((double) params->rate);
673
674         /* Scheduling loop detection */
675         port->pipe_loop = RTE_SCHED_PIPE_INVALID;
676         port->pipe_exhaustion = 0;
677
678         /* Grinders */
679         port->busy_grinders = 0;
680         port->pkts_out = NULL;
681         port->n_pkts_out = 0;
682         
683         /* Queue base calculation */
684         rte_sched_port_config_qsize(port);
685         
686         /* Large data structures */
687         port->subport = (struct rte_sched_subport *) (port->memory + rte_sched_port_get_array_base(params, e_RTE_SCHED_PORT_ARRAY_SUBPORT));
688         port->pipe = (struct rte_sched_pipe *) (port->memory + rte_sched_port_get_array_base(params, e_RTE_SCHED_PORT_ARRAY_PIPE));
689         port->queue = (struct rte_sched_queue *) (port->memory + rte_sched_port_get_array_base(params, e_RTE_SCHED_PORT_ARRAY_QUEUE));
690         port->queue_extra = (struct rte_sched_queue_extra *) (port->memory + rte_sched_port_get_array_base(params, e_RTE_SCHED_PORT_ARRAY_QUEUE_EXTRA));
691         port->pipe_profiles = (struct rte_sched_pipe_profile *) (port->memory + rte_sched_port_get_array_base(params, e_RTE_SCHED_PORT_ARRAY_PIPE_PROFILES));
692         port->bmp_array =  port->memory + rte_sched_port_get_array_base(params, e_RTE_SCHED_PORT_ARRAY_BMP_ARRAY);
693         port->queue_array = (struct rte_mbuf **) (port->memory + rte_sched_port_get_array_base(params, e_RTE_SCHED_PORT_ARRAY_QUEUE_ARRAY));
694
695         /* Pipe profile table */
696         rte_sched_port_config_pipe_profile_table(port, params);
697         
698         /* Bitmap */
699         n_queues_per_port = rte_sched_port_queues_per_port(port);
700         bmp_mem_size = rte_bitmap_get_memory_footprint(n_queues_per_port);
701         port->bmp = rte_bitmap_init(n_queues_per_port, port->bmp_array, bmp_mem_size);
702         if (port->bmp == NULL) {
703                 RTE_LOG(INFO, SCHED, "Bitmap init error\n");
704                 return NULL;
705         }
706         for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i ++) {
707                 port->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
708         }
709         
710         return port;
711 }
712
713 void 
714 rte_sched_port_free(struct rte_sched_port *port)
715 {
716         /* Check user parameters */
717         if (port == NULL){
718                 return;
719         }
720         rte_bitmap_free(port->bmp);
721         
722         return;
723 }
724
725 static void
726 rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
727 {
728         struct rte_sched_subport *s = port->subport + i;
729         
730         RTE_LOG(INFO, SCHED, "Low level config for subport %u:\n"       
731                 "\tToken bucket: period = %u, credits per period = %u, size = %u\n"
732                 "\tTraffic classes: period = %u, credits per period = [%u, %u, %u, %u]\n"
733                 "\tTraffic class 3 oversubscription: wm min = %u, wm max = %u\n",
734                 i,
735                 
736                 /* Token bucket */
737                 s->tb_period,
738                 s->tb_credits_per_period,
739                 s->tb_size,
740                 
741                 /* Traffic classes */
742                 s->tc_period,
743                 s->tc_credits_per_period[0],
744                 s->tc_credits_per_period[1],
745                 s->tc_credits_per_period[2],
746                 s->tc_credits_per_period[3],
747                 
748                 /* Traffic class 3 oversubscription */
749                 s->tc_ov_wm_min,
750                 s->tc_ov_wm_max);
751 }
752
753 int
754 rte_sched_subport_config(struct rte_sched_port *port, 
755         uint32_t subport_id,
756         struct rte_sched_subport_params *params)
757 {
758         struct rte_sched_subport *s;
759         uint32_t i;
760         
761         /* Check user parameters */
762         if ((port == NULL) ||
763             (subport_id >= port->n_subports_per_port) ||
764                 (params == NULL)) {
765                 return -1;
766         }
767         
768         if ((params->tb_rate == 0) || (params->tb_rate > port->rate)) {
769                 return -2;
770         }
771         
772         if (params->tb_size == 0) {
773                 return -3;
774         }
775         
776         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i ++) {
777                 if ((params->tc_rate[i] == 0) || (params->tc_rate[i] > params->tb_rate)) {
778                         return -4;
779                 }
780         }
781         
782         if (params->tc_period == 0) {
783                 return -5;
784         }
785         
786         s = port->subport + subport_id;
787         
788         /* Token Bucket (TB) */
789         if (params->tb_rate == port->rate) {
790                 s->tb_credits_per_period = 1;
791                 s->tb_period = 1;
792         } else {
793                 double tb_rate = ((double) params->tb_rate) / ((double) port->rate);
794                 double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
795                 
796                 rte_approx(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
797         }
798         s->tb_size = params->tb_size;
799         s->tb_time = port->time;
800         s->tb_credits = s->tb_size / 2;
801         
802         /* Traffic Classes (TCs) */
803         s->tc_period = (uint32_t) rte_sched_time_ms_to_bytes(params->tc_period, port->rate);
804         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i ++) {
805                 s->tc_credits_per_period[i] = (uint32_t) rte_sched_time_ms_to_bytes(params->tc_period, params->tc_rate[i]);
806         }
807         s->tc_time = port->time + s->tc_period;
808         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i ++) {
809                 s->tc_credits[i] = s->tc_credits_per_period[i];
810         }
811         
812 #ifdef RTE_SCHED_SUBPORT_TC_OV
813         /* TC oversubscription */
814         s->tc_ov_wm_min = port->mtu;
815         s->tc_ov_wm_max = (uint32_t) rte_sched_time_ms_to_bytes(params->tc_period, port->pipe_tc3_rate_max);
816         s->tc_ov_wm = s->tc_ov_wm_max;
817         s->tc_ov_period_id = 0;
818         s->tc_ov = 0;
819         s->tc_ov_n = 0;
820         s->tc_ov_rate = 0;
821 #endif
822         
823         rte_sched_port_log_subport_config(port, subport_id);
824         
825         return 0;
826 }
827
828 int
829 rte_sched_pipe_config(struct rte_sched_port *port,
830         uint32_t subport_id, 
831         uint32_t pipe_id,
832         int32_t pipe_profile)
833 {
834         struct rte_sched_subport *s;
835         struct rte_sched_pipe *p;
836         struct rte_sched_pipe_profile *params;
837         uint32_t deactivate, profile, i;
838         
839         /* Check user parameters */
840         profile = (uint32_t) pipe_profile;
841         deactivate = (pipe_profile < 0);
842         if ((port == NULL) ||
843             (subport_id >= port->n_subports_per_port) ||
844                 (pipe_id >= port->n_pipes_per_subport) ||
845                 ((!deactivate) && (profile >= port->n_pipe_profiles))) {
846                 return -1;
847         }
848         
849         /* Check that subport configuration is valid */
850         s = port->subport + subport_id;
851         if (s->tb_period == 0) {
852                 return -2;
853         }
854         
855         p = port->pipe + (subport_id * port->n_pipes_per_subport + pipe_id);
856         
857         /* Handle the case when pipe already has a valid configuration */
858         if (p->tb_time) {
859                 params = port->pipe_profiles + p->profile;
860
861 #ifdef RTE_SCHED_SUBPORT_TC_OV
862                 double subport_tc3_rate = ((double) s->tc_credits_per_period[3]) / ((double) s->tc_period);
863                 double pipe_tc3_rate = ((double) params->tc_credits_per_period[3]) / ((double) params->tc_period);
864                 uint32_t tc3_ov = s->tc_ov;
865                 
866                 /* Unplug pipe from its subport */
867                 s->tc_ov_n -= params->tc_ov_weight;
868                 s->tc_ov_rate -= pipe_tc3_rate;
869                 s->tc_ov = s->tc_ov_rate > subport_tc3_rate;
870                 
871                 if (s->tc_ov != tc3_ov) {
872                         RTE_LOG(INFO, SCHED, "Subport %u TC3 oversubscription is OFF (%.4lf >= %.4lf)\n", 
873                                 subport_id, subport_tc3_rate, s->tc_ov_rate);
874                 }
875 #endif
876                 
877                 /* Reset the pipe */
878                 memset(p, 0, sizeof(struct rte_sched_pipe));
879         }
880         
881         if (deactivate) {
882                 return 0;
883         }
884         
885         /* Apply the new pipe configuration */
886         p->profile = profile;
887         params = port->pipe_profiles + p->profile;
888
889         /* Token Bucket (TB) */
890         p->tb_time = port->time;
891         p->tb_credits = params->tb_size / 2;
892         
893         /* Traffic Classes (TCs) */
894         p->tc_time = port->time + params->tc_period;
895         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i ++) {
896                 p->tc_credits[i] = params->tc_credits_per_period[i];
897         }
898         
899 #ifdef RTE_SCHED_SUBPORT_TC_OV
900         {
901                 /* Subport TC3 oversubscription */
902                 double subport_tc3_rate = ((double) s->tc_credits_per_period[3]) / ((double) s->tc_period);
903                 double pipe_tc3_rate = ((double) params->tc_credits_per_period[3]) / ((double) params->tc_period);
904                 uint32_t tc3_ov = s->tc_ov;
905                         
906                 s->tc_ov_n += params->tc_ov_weight;
907                 s->tc_ov_rate += pipe_tc3_rate;
908                 s->tc_ov = s->tc_ov_rate > subport_tc3_rate;
909                 
910                 if (s->tc_ov != tc3_ov) {
911                         RTE_LOG(INFO, SCHED, "Subport %u TC3 oversubscription is ON (%.4lf < %.4lf)\n", 
912                                 subport_id, subport_tc3_rate, s->tc_ov_rate);
913                 }
914                 p->tc_ov_period_id = s->tc_ov_period_id;
915                 p->tc_ov_credits = s->tc_ov_wm;
916         }
917 #endif
918         
919         return 0;
920 }
921
922 int
923 rte_sched_subport_read_stats(struct rte_sched_port *port,
924         uint32_t subport_id,
925         struct rte_sched_subport_stats *stats,
926         uint32_t *tc_ov)
927 {
928         struct rte_sched_subport *s;
929         
930         /* Check user parameters */
931         if ((port == NULL) ||
932             (subport_id >= port->n_subports_per_port) ||
933                 (stats == NULL) ||
934                 (tc_ov == NULL)) {
935                 return -1;
936         }
937         s = port->subport + subport_id;
938
939         /* Copy subport stats and clear */
940         memcpy(stats, &s->stats, sizeof(struct rte_sched_subport_stats));
941         memset(&s->stats, 0, sizeof(struct rte_sched_subport_stats));
942         
943         /* Subport TC ovesubscription status */
944         *tc_ov = s->tc_ov;
945         
946         return 0;
947 }
948
949 int
950 rte_sched_queue_read_stats(struct rte_sched_port *port,
951         uint32_t queue_id,
952         struct rte_sched_queue_stats *stats,
953         uint16_t *qlen)
954 {
955         struct rte_sched_queue *q;
956         struct rte_sched_queue_extra *qe;
957         
958         /* Check user parameters */
959         if ((port == NULL) ||
960             (queue_id >= rte_sched_port_queues_per_port(port)) ||
961                 (stats == NULL) ||
962                 (qlen == NULL)) {
963                 return -1;
964         }
965         q = port->queue + queue_id;
966         qe = port->queue_extra + queue_id;
967
968         /* Copy queue stats and clear */
969         memcpy(stats, &qe->stats, sizeof(struct rte_sched_queue_stats));
970         memset(&qe->stats, 0, sizeof(struct rte_sched_queue_stats));
971         
972         /* Queue length */
973         *qlen = q->qw - q->qr;
974         
975         return 0;
976 }
977
978 static inline uint32_t
979 rte_sched_port_qindex(struct rte_sched_port *port, uint32_t subport, uint32_t pipe, uint32_t traffic_class, uint32_t queue)
980 {
981         uint32_t result;
982         
983         result = subport * port->n_pipes_per_subport + pipe;
984         result = result * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE + traffic_class;
985         result = result * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue;
986         
987         return result;
988 }
989
990 static inline struct rte_mbuf **
991 rte_sched_port_qbase(struct rte_sched_port *port, uint32_t qindex)
992 {
993         uint32_t pindex = qindex >> 4;
994         uint32_t qpos = qindex & 0xF;
995         
996         return (port->queue_array + pindex * port->qsize_sum + port->qsize_add[qpos]);
997 }
998
999 static inline uint16_t
1000 rte_sched_port_qsize(struct rte_sched_port *port, uint32_t qindex)
1001 {
1002         uint32_t tc = (qindex >> 2) & 0x3;
1003         
1004         return port->qsize[tc];
1005 }
1006
1007 #if RTE_SCHED_DEBUG
1008
1009 static inline int
1010 rte_sched_port_queue_is_empty(struct rte_sched_port *port, uint32_t qindex)
1011 {
1012         struct rte_sched_queue *queue = port->queue + qindex;
1013         
1014         return (queue->qr == queue->qw);
1015 }
1016
1017 static inline int
1018 rte_sched_port_queue_is_full(struct rte_sched_port *port, uint32_t qindex)
1019 {
1020         struct rte_sched_queue *queue = port->queue + qindex;
1021         uint16_t qsize = rte_sched_port_qsize(port, qindex);
1022         uint16_t qlen = q->qw - q->qr;
1023         
1024         return (qlen >= qsize);
1025 }
1026
1027 #endif /* RTE_SCHED_DEBUG */
1028
1029 #ifdef RTE_SCHED_COLLECT_STATS
1030
1031 static inline void
1032 rte_sched_port_update_subport_stats(struct rte_sched_port *port, uint32_t qindex, struct rte_mbuf *pkt)
1033 {
1034         struct rte_sched_subport *s = port->subport + (qindex / rte_sched_port_queues_per_subport(port));
1035         uint32_t tc_index = (qindex >> 2) & 0x3;
1036         uint32_t pkt_len = pkt->pkt.pkt_len;
1037         
1038         s->stats.n_pkts_tc[tc_index] += 1;
1039         s->stats.n_bytes_tc[tc_index] += pkt_len;
1040 }
1041
1042 static inline void
1043 rte_sched_port_update_subport_stats_on_drop(struct rte_sched_port *port, uint32_t qindex, struct rte_mbuf *pkt)
1044 {
1045         struct rte_sched_subport *s = port->subport + (qindex / rte_sched_port_queues_per_subport(port));
1046         uint32_t tc_index = (qindex >> 2) & 0x3;
1047         uint32_t pkt_len = pkt->pkt.pkt_len;
1048         
1049         s->stats.n_pkts_tc_dropped[tc_index] += 1;
1050         s->stats.n_bytes_tc_dropped[tc_index] += pkt_len;
1051 }
1052
1053 static inline void
1054 rte_sched_port_update_queue_stats(struct rte_sched_port *port, uint32_t qindex, struct rte_mbuf *pkt)
1055 {
1056         struct rte_sched_queue_extra *qe = port->queue_extra + qindex;
1057         uint32_t pkt_len = pkt->pkt.pkt_len;
1058         
1059         qe->stats.n_pkts += 1;
1060         qe->stats.n_bytes += pkt_len;
1061 }
1062
1063 static inline void
1064 rte_sched_port_update_queue_stats_on_drop(struct rte_sched_port *port, uint32_t qindex, struct rte_mbuf *pkt)
1065 {
1066         struct rte_sched_queue_extra *qe = port->queue_extra + qindex;
1067         uint32_t pkt_len = pkt->pkt.pkt_len;
1068         
1069         qe->stats.n_pkts_dropped += 1;
1070         qe->stats.n_bytes_dropped += pkt_len;
1071 }
1072
1073 #endif /* RTE_SCHED_COLLECT_STATS */
1074
1075 #ifdef RTE_SCHED_RED
1076
1077 static inline int
1078 rte_sched_port_red_drop(struct rte_sched_port *port, struct rte_mbuf *pkt, uint32_t qindex, uint16_t qlen)
1079 {
1080         struct rte_sched_queue_extra *qe;
1081         struct rte_red_config *red_cfg;
1082     struct rte_red *red;
1083         uint32_t tc_index;
1084         enum rte_meter_color color;
1085         
1086         tc_index = (qindex >> 2) & 0x3;
1087         color = rte_sched_port_pkt_read_color(pkt);
1088         red_cfg = &port->red_config[tc_index][color];
1089
1090         qe = port->queue_extra + qindex;
1091         red = &qe->red;
1092
1093         return rte_red_enqueue(red_cfg, red, qlen, port->time);
1094 }
1095
1096 static inline void
1097 rte_sched_port_set_queue_empty_timestamp(struct rte_sched_port *port, uint32_t qindex)
1098 {
1099         struct rte_sched_queue_extra *qe;
1100     struct rte_red *red;
1101         
1102         qe = port->queue_extra + qindex;
1103         red = &qe->red;
1104
1105         rte_red_mark_queue_empty(red, port->time);
1106 }
1107
1108 #else
1109
1110 #define rte_sched_port_red_drop(port, pkt, qindex, qlen)             0
1111
1112 #define rte_sched_port_set_queue_empty_timestamp(port, qindex)
1113
1114 #endif /* RTE_SCHED_RED */
1115
1116 #if RTE_SCHED_DEBUG
1117
1118 static inline int
1119 debug_pipe_is_empty(struct rte_sched_port *port, uint32_t pindex)
1120 {
1121         uint32_t qindex, i;
1122
1123         qindex = pindex << 4;
1124         
1125         for (i = 0; i < 16; i ++){
1126                 uint32_t queue_empty = rte_sched_port_queue_is_empty(port, qindex + i);
1127                 uint32_t bmp_bit_clear = (rte_bitmap_get(port->bmp, qindex + i) == 0);
1128                 
1129                 if (queue_empty != bmp_bit_clear){
1130                         rte_panic("Queue status mismatch for queue %u of pipe %u\n", i, pindex);
1131                 }
1132                 
1133                 if (!queue_empty){
1134                         return 0;
1135                 }
1136         }
1137         
1138         return 1;
1139 }
1140
1141 static inline void
1142 debug_check_queue_slab(struct rte_sched_port *port, uint32_t bmp_pos, uint64_t bmp_slab)
1143 {
1144         uint64_t mask;
1145         uint32_t i, panic;
1146         
1147         if (bmp_slab == 0){
1148                 rte_panic("Empty slab at position %u\n", bmp_pos);
1149         }
1150         
1151         panic = 0;
1152         for (i = 0, mask = 1; i < 64; i ++, mask <<= 1) {
1153                 if (mask & bmp_slab){
1154                         if (rte_sched_port_queue_is_empty(port, bmp_pos + i)) {
1155                                 printf("Queue %u (slab offset %u) is empty\n", bmp_pos + i, i);
1156                                 panic = 1;
1157                         }
1158                 }
1159         }
1160         
1161         if (panic){
1162                 rte_panic("Empty queues in slab 0x%" PRIx64 "starting at position %u\n",
1163                         bmp_slab, bmp_pos);
1164         }
1165 }
1166
1167 #endif /* RTE_SCHED_DEBUG */
1168
1169 static inline uint32_t
1170 rte_sched_port_enqueue_qptrs_prefetch0(struct rte_sched_port *port, struct rte_mbuf *pkt)
1171 {
1172         struct rte_sched_queue *q;
1173 #ifdef RTE_SCHED_COLLECT_STATS
1174         struct rte_sched_queue_extra *qe;
1175 #endif
1176         uint32_t subport, pipe, traffic_class, queue, qindex;
1177
1178         rte_sched_port_pkt_read_tree_path(pkt, &subport, &pipe, &traffic_class, &queue);
1179         
1180         qindex = rte_sched_port_qindex(port, subport, pipe, traffic_class, queue);
1181         q = port->queue + qindex;
1182         rte_prefetch0(q);
1183 #ifdef RTE_SCHED_COLLECT_STATS
1184         qe = port->queue_extra + qindex;
1185         rte_prefetch0(qe);
1186 #endif
1187         
1188         return qindex;
1189 }
1190
1191 static inline void
1192 rte_sched_port_enqueue_qwa_prefetch0(struct rte_sched_port *port, uint32_t qindex, struct rte_mbuf **qbase)
1193 {       
1194         struct rte_sched_queue *q;
1195         struct rte_mbuf **q_qw;
1196         uint16_t qsize; 
1197         
1198         q = port->queue + qindex;
1199         qsize = rte_sched_port_qsize(port, qindex);
1200         q_qw = qbase + (q->qw & (qsize - 1));
1201         
1202         rte_prefetch0(q_qw);
1203         rte_bitmap_prefetch0(port->bmp, qindex);
1204 }
1205
1206 static inline int
1207 rte_sched_port_enqueue_qwa(struct rte_sched_port *port, uint32_t qindex, struct rte_mbuf **qbase, struct rte_mbuf *pkt)
1208 {
1209         struct rte_sched_queue *q;
1210         uint16_t qsize;
1211         uint16_t qlen;
1212
1213         q = port->queue + qindex;
1214         qsize = rte_sched_port_qsize(port, qindex);
1215         qlen = q->qw - q->qr;
1216
1217         /* Drop the packet (and update drop stats) when queue is full */
1218         if (unlikely(rte_sched_port_red_drop(port, pkt, qindex, qlen) || (qlen >= qsize))) {
1219                 rte_pktmbuf_free(pkt);
1220 #ifdef RTE_SCHED_COLLECT_STATS
1221                 rte_sched_port_update_subport_stats_on_drop(port, qindex, pkt);
1222                 rte_sched_port_update_queue_stats_on_drop(port, qindex, pkt);
1223 #endif
1224                 return 0;
1225         }
1226         
1227         /* Enqueue packet */
1228         qbase[q->qw & (qsize - 1)] = pkt;
1229         q->qw ++;
1230         
1231         /* Activate queue in the port bitmap */
1232         rte_bitmap_set(port->bmp, qindex);
1233         
1234         /* Statistics */
1235 #ifdef RTE_SCHED_COLLECT_STATS
1236         rte_sched_port_update_subport_stats(port, qindex, pkt);
1237         rte_sched_port_update_queue_stats(port, qindex, pkt);
1238 #endif
1239
1240         return 1;
1241 }
1242
1243 #if RTE_SCHED_ENQUEUE == 0
1244
1245 int 
1246 rte_sched_port_enqueue(struct rte_sched_port *port, struct rte_mbuf **pkts, uint32_t n_pkts)
1247 {
1248         uint32_t result, i;
1249         
1250         result = 0;
1251         
1252         for (i = 0; i < n_pkts; i ++) {
1253                 struct rte_mbuf *pkt;
1254                 struct rte_mbuf **q_base;
1255                 uint32_t subport, pipe, traffic_class, queue, qindex;
1256                 
1257                 pkt = pkts[i];
1258                 
1259                 rte_sched_port_pkt_read_tree_path(pkt, &subport, &pipe, &traffic_class, &queue);
1260
1261                 qindex = rte_sched_port_qindex(port, subport, pipe, traffic_class, queue);
1262                 
1263                 q_base = rte_sched_port_qbase(port, qindex);
1264
1265                 result += rte_sched_port_enqueue_qwa(port, qindex, q_base, pkt);
1266         }
1267         
1268         return result;
1269 }
1270
1271 #else
1272
1273 /* The enqueue function implements a 4-level pipeline with each stage processing 
1274  * two different packets. The purpose of using a pipeline is to hide the latency 
1275  * of prefetching the data structures. The naming convention is presented in the
1276  * diagram below:
1277  * 
1278  *   p00  _______   p10  _______   p20  _______   p30  _______       
1279  * ----->|       |----->|       |----->|       |----->|       |----->
1280  *       |   0   |      |   1   |      |   2   |      |   3   |      
1281  * ----->|_______|----->|_______|----->|_______|----->|_______|----->
1282  *   p01            p11            p21            p31                
1283  *
1284  ***/
1285 int
1286 rte_sched_port_enqueue(struct rte_sched_port *port, struct rte_mbuf **pkts, uint32_t n_pkts)
1287 {
1288         struct rte_mbuf *pkt00, *pkt01, *pkt10, *pkt11, *pkt20, *pkt21, *pkt30, *pkt31, *pkt_last;
1289         struct rte_mbuf **q00_base, **q01_base, **q10_base, **q11_base, **q20_base, **q21_base, **q30_base, **q31_base, **q_last_base;
1290         uint32_t q00, q01, q10, q11, q20, q21, q30, q31, q_last;
1291         uint32_t r00, r01, r10, r11, r20, r21, r30, r31, r_last;
1292         uint32_t result, i;
1293         
1294         result = 0;
1295         
1296         /* Less then 6 input packets available, which is not enough to feed the pipeline */
1297         if (unlikely(n_pkts < 6)) {
1298                 struct rte_mbuf **q_base[5];
1299                 uint32_t q[5];
1300                 
1301                 /* Prefetch the mbuf structure of each packet */
1302                 for (i = 0; i < n_pkts; i ++) {
1303                         rte_prefetch0(pkts[i]);
1304                 }
1305                 
1306                 /* Prefetch the queue structure for each queue */
1307                 for (i = 0; i < n_pkts; i ++) {
1308                         q[i] = rte_sched_port_enqueue_qptrs_prefetch0(port, pkts[i]);
1309                 }
1310                 
1311                 /* Prefetch the write pointer location of each queue */
1312                 for (i = 0; i < n_pkts; i ++) {
1313                         q_base[i] = rte_sched_port_qbase(port, q[i]);
1314                         rte_sched_port_enqueue_qwa_prefetch0(port, q[i], q_base[i]);
1315                 }
1316                 
1317                 /* Write each packet to its queue */
1318                 for (i = 0; i < n_pkts; i ++) {
1319                         result += rte_sched_port_enqueue_qwa(port, q[i], q_base[i], pkts[i]);
1320                 }
1321                 
1322                 return result;
1323         }
1324         
1325         /* Feed the first 3 stages of the pipeline (6 packets needed) */
1326         pkt20 = pkts[0];
1327         pkt21 = pkts[1];
1328         rte_prefetch0(pkt20);
1329         rte_prefetch0(pkt21);
1330         
1331         pkt10 = pkts[2];
1332         pkt11 = pkts[3];
1333         rte_prefetch0(pkt10);
1334         rte_prefetch0(pkt11);
1335
1336         q20 = rte_sched_port_enqueue_qptrs_prefetch0(port, pkt20);
1337         q21 = rte_sched_port_enqueue_qptrs_prefetch0(port, pkt21);
1338
1339         pkt00 = pkts[4];
1340         pkt01 = pkts[5];
1341         rte_prefetch0(pkt00);
1342         rte_prefetch0(pkt01);
1343         
1344         q10 = rte_sched_port_enqueue_qptrs_prefetch0(port, pkt10);
1345         q11 = rte_sched_port_enqueue_qptrs_prefetch0(port, pkt11);
1346
1347         q20_base = rte_sched_port_qbase(port, q20);
1348         q21_base = rte_sched_port_qbase(port, q21);     
1349         rte_sched_port_enqueue_qwa_prefetch0(port, q20, q20_base);
1350         rte_sched_port_enqueue_qwa_prefetch0(port, q21, q21_base);
1351         
1352         /* Run the pipeline */
1353         for (i = 6; i < (n_pkts & (~1)); i += 2) {      
1354                 /* Propagate stage inputs */
1355                 pkt30 = pkt20;
1356                 pkt31 = pkt21;
1357                 pkt20 = pkt10;
1358                 pkt21 = pkt11;
1359                 pkt10 = pkt00;
1360                 pkt11 = pkt01;
1361                 q30 = q20;
1362                 q31 = q21;
1363                 q20 = q10;
1364                 q21 = q11;
1365                 q30_base = q20_base;
1366                 q31_base = q21_base;
1367                 
1368                 /* Stage 0: Get packets in */
1369                 pkt00 = pkts[i];
1370                 pkt01 = pkts[i + 1];
1371                 rte_prefetch0(pkt00);
1372                 rte_prefetch0(pkt01);
1373                 
1374                 /* Stage 1: Prefetch queue structure storing queue pointers */
1375                 q10 = rte_sched_port_enqueue_qptrs_prefetch0(port, pkt10);
1376                 q11 = rte_sched_port_enqueue_qptrs_prefetch0(port, pkt11);
1377                 
1378                 /* Stage 2: Prefetch queue write location */
1379                 q20_base = rte_sched_port_qbase(port, q20);
1380                 q21_base = rte_sched_port_qbase(port, q21);
1381                 rte_sched_port_enqueue_qwa_prefetch0(port, q20, q20_base);
1382                 rte_sched_port_enqueue_qwa_prefetch0(port, q21, q21_base);
1383                 
1384                 /* Stage 3: Write packet to queue and activate queue */
1385                 r30 = rte_sched_port_enqueue_qwa(port, q30, q30_base, pkt30);
1386                 r31 = rte_sched_port_enqueue_qwa(port, q31, q31_base, pkt31);
1387                 result += r30 + r31;
1388         }
1389         
1390         /* Drain the pipeline (exactly 6 packets). Handle the last packet in the case
1391         of an odd number of input packets. */
1392         pkt_last = pkts[n_pkts - 1];
1393         rte_prefetch0(pkt_last);
1394         
1395         q00 = rte_sched_port_enqueue_qptrs_prefetch0(port, pkt00);
1396         q01 = rte_sched_port_enqueue_qptrs_prefetch0(port, pkt01);
1397
1398         q10_base = rte_sched_port_qbase(port, q10);
1399         q11_base = rte_sched_port_qbase(port, q11);
1400         rte_sched_port_enqueue_qwa_prefetch0(port, q10, q10_base);
1401         rte_sched_port_enqueue_qwa_prefetch0(port, q11, q11_base);
1402                 
1403         r20 = rte_sched_port_enqueue_qwa(port, q20, q20_base, pkt20);
1404         r21 = rte_sched_port_enqueue_qwa(port, q21, q21_base, pkt21);
1405         result += r20 + r21;
1406         
1407         q_last = rte_sched_port_enqueue_qptrs_prefetch0(port, pkt_last);
1408
1409         q00_base = rte_sched_port_qbase(port, q00);
1410         q01_base = rte_sched_port_qbase(port, q01);
1411         rte_sched_port_enqueue_qwa_prefetch0(port, q00, q00_base);
1412         rte_sched_port_enqueue_qwa_prefetch0(port, q01, q01_base);
1413         
1414         r10 = rte_sched_port_enqueue_qwa(port, q10, q10_base, pkt10);
1415         r11 = rte_sched_port_enqueue_qwa(port, q11, q11_base, pkt11);
1416         result += r10 + r11;
1417
1418         q_last_base = rte_sched_port_qbase(port, q_last);
1419         rte_sched_port_enqueue_qwa_prefetch0(port, q_last, q_last_base);
1420
1421         r00 = rte_sched_port_enqueue_qwa(port, q00, q00_base, pkt00);
1422         r01 = rte_sched_port_enqueue_qwa(port, q01, q01_base, pkt01);
1423         result += r00 + r01;
1424
1425         if (n_pkts & 1) {
1426                 r_last = rte_sched_port_enqueue_qwa(port, q_last, q_last_base, pkt_last);
1427                 result += r_last;
1428         }
1429         
1430         return result;
1431 }
1432
1433 #endif /* RTE_SCHED_ENQUEUE */
1434
1435 #if RTE_SCHED_TS_CREDITS_UPDATE == 0
1436
1437 #define grinder_credits_update(port, pos)
1438
1439 #elif !defined(RTE_SCHED_SUBPORT_TC_OV)
1440
1441 static inline void
1442 grinder_credits_update(struct rte_sched_port *port, uint32_t pos)
1443 {
1444         struct rte_sched_grinder *grinder = port->grinder + pos;
1445         struct rte_sched_subport *subport = grinder->subport;
1446         struct rte_sched_pipe *pipe = grinder->pipe;
1447         struct rte_sched_pipe_profile *params = grinder->pipe_params;
1448         uint64_t n_periods;
1449         
1450         /* Subport TB */
1451         n_periods = (port->time - subport->tb_time) / subport->tb_period;
1452         subport->tb_credits += n_periods * subport->tb_credits_per_period;
1453         subport->tb_credits = rte_sched_min_val_2_u32(subport->tb_credits, subport->tb_size);
1454         subport->tb_time += n_periods * subport->tb_period;
1455         
1456         /* Pipe TB */
1457         n_periods = (port->time - pipe->tb_time) / params->tb_period;
1458         pipe->tb_credits += n_periods * params->tb_credits_per_period;
1459         pipe->tb_credits = rte_sched_min_val_2_u32(pipe->tb_credits, params->tb_size);
1460         pipe->tb_time += n_periods * params->tb_period;
1461
1462         /* Subport TCs */
1463         if (unlikely(port->time >= subport->tc_time)) {
1464                 subport->tc_credits[0] = subport->tc_credits_per_period[0];
1465                 subport->tc_credits[1] = subport->tc_credits_per_period[1];
1466                 subport->tc_credits[2] = subport->tc_credits_per_period[2];
1467                 subport->tc_credits[3] = subport->tc_credits_per_period[3];
1468                 subport->tc_time = port->time + subport->tc_period;
1469         }
1470         
1471         /* Pipe TCs */
1472         if (unlikely(port->time >= pipe->tc_time)) {
1473                 pipe->tc_credits[0] = params->tc_credits_per_period[0];
1474                 pipe->tc_credits[1] = params->tc_credits_per_period[1];
1475                 pipe->tc_credits[2] = params->tc_credits_per_period[2];
1476                 pipe->tc_credits[3] = params->tc_credits_per_period[3];
1477                 pipe->tc_time = port->time + params->tc_period;
1478         }
1479 }
1480
1481 #else
1482
1483 static inline uint32_t
1484 grinder_tc_ov_credits_update(struct rte_sched_port *port, uint32_t pos)
1485 {
1486         struct rte_sched_grinder *grinder = port->grinder + pos;
1487         struct rte_sched_subport *subport = grinder->subport;
1488         uint32_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
1489         uint32_t tc_ov_consumption_max;
1490         uint32_t tc_ov_wm = subport->tc_ov_wm;
1491         
1492         if (subport->tc_ov == 0) {
1493                 return subport->tc_ov_wm_max;
1494         }
1495         
1496         tc_ov_consumption[0] = subport->tc_credits_per_period[0] - subport->tc_credits[0];
1497         tc_ov_consumption[1] = subport->tc_credits_per_period[1] - subport->tc_credits[1];
1498         tc_ov_consumption[2] = subport->tc_credits_per_period[2] - subport->tc_credits[2];
1499         tc_ov_consumption[3] = subport->tc_credits_per_period[3] - subport->tc_credits[3];
1500         
1501         tc_ov_consumption_max = subport->tc_credits_per_period[3] - 
1502                 (tc_ov_consumption[0] + tc_ov_consumption[1] + tc_ov_consumption[2]);
1503         
1504         if (tc_ov_consumption[3] > (tc_ov_consumption_max - port->mtu)) {
1505                 tc_ov_wm  -= tc_ov_wm >> 7;
1506                 if (tc_ov_wm < subport->tc_ov_wm_min) {
1507                         tc_ov_wm = subport->tc_ov_wm_min;
1508                 }
1509                 return tc_ov_wm;
1510         }
1511         
1512         tc_ov_wm += (tc_ov_wm >> 7) + 1;
1513         if (tc_ov_wm > subport->tc_ov_wm_max) {
1514                 tc_ov_wm = subport->tc_ov_wm_max;
1515         }
1516         return tc_ov_wm;
1517 }
1518
1519 static inline void
1520 grinder_credits_update(struct rte_sched_port *port, uint32_t pos)
1521 {
1522         struct rte_sched_grinder *grinder = port->grinder + pos;
1523         struct rte_sched_subport *subport = grinder->subport;
1524         struct rte_sched_pipe *pipe = grinder->pipe;
1525         struct rte_sched_pipe_profile *params = grinder->pipe_params;
1526         uint64_t n_periods;
1527         
1528         /* Subport TB */
1529         n_periods = (port->time - subport->tb_time) / subport->tb_period;
1530         subport->tb_credits += n_periods * subport->tb_credits_per_period;
1531         subport->tb_credits = rte_sched_min_val_2_u32(subport->tb_credits, subport->tb_size);
1532         subport->tb_time += n_periods * subport->tb_period;
1533         
1534         /* Pipe TB */
1535         n_periods = (port->time - pipe->tb_time) / params->tb_period;
1536         pipe->tb_credits += n_periods * params->tb_credits_per_period;
1537         pipe->tb_credits = rte_sched_min_val_2_u32(pipe->tb_credits, params->tb_size);
1538         pipe->tb_time += n_periods * params->tb_period;
1539
1540         /* Subport TCs */
1541         if (unlikely(port->time >= subport->tc_time)) {
1542                 subport->tc_ov_wm = grinder_tc_ov_credits_update(port, pos);
1543
1544                 subport->tc_credits[0] = subport->tc_credits_per_period[0];
1545                 subport->tc_credits[1] = subport->tc_credits_per_period[1];
1546                 subport->tc_credits[2] = subport->tc_credits_per_period[2];
1547                 subport->tc_credits[3] = subport->tc_credits_per_period[3];
1548                 
1549                 subport->tc_time = port->time + subport->tc_period;
1550                 subport->tc_ov_period_id ++;
1551         }
1552
1553         /* Pipe TCs */
1554         if (unlikely(port->time >= pipe->tc_time)) {
1555                 pipe->tc_credits[0] = params->tc_credits_per_period[0];
1556                 pipe->tc_credits[1] = params->tc_credits_per_period[1];
1557                 pipe->tc_credits[2] = params->tc_credits_per_period[2];
1558                 pipe->tc_credits[3] = params->tc_credits_per_period[3];
1559                 pipe->tc_time = port->time + params->tc_period;
1560         }
1561         
1562         /* Pipe TCs - Oversubscription */
1563         if (unlikely(pipe->tc_ov_period_id != subport->tc_ov_period_id)) {
1564                 pipe->tc_ov_credits = subport->tc_ov_wm * params->tc_ov_weight;
1565                 
1566                 pipe->tc_ov_period_id = subport->tc_ov_period_id;
1567         }
1568 }
1569
1570 #endif /* RTE_SCHED_TS_CREDITS_UPDATE, RTE_SCHED_SUBPORT_TC_OV */
1571
1572 #ifndef RTE_SCHED_SUBPORT_TC_OV
1573
1574 static inline int
1575 grinder_credits_check(struct rte_sched_port *port, uint32_t pos)
1576 {
1577         struct rte_sched_grinder *grinder = port->grinder + pos;
1578         struct rte_sched_subport *subport = grinder->subport;
1579         struct rte_sched_pipe *pipe = grinder->pipe;
1580         struct rte_mbuf *pkt = grinder->pkt;
1581         uint32_t tc_index = grinder->tc_index;
1582         uint32_t pkt_len = pkt->pkt.pkt_len + port->frame_overhead;
1583         uint32_t subport_tb_credits = subport->tb_credits;
1584         uint32_t subport_tc_credits = subport->tc_credits[tc_index];
1585         uint32_t pipe_tb_credits = pipe->tb_credits;
1586         uint32_t pipe_tc_credits = pipe->tc_credits[tc_index];
1587         int enough_credits;
1588
1589         /* Check queue credits */
1590         enough_credits = (pkt_len <= subport_tb_credits) &&
1591                 (pkt_len <= subport_tc_credits) &&
1592                 (pkt_len <= pipe_tb_credits) &&
1593                 (pkt_len <= pipe_tc_credits);
1594         
1595         if (!enough_credits) {
1596                 return 0;
1597         }
1598         
1599         /* Update port credits */
1600         subport->tb_credits -= pkt_len;
1601         subport->tc_credits[tc_index] -= pkt_len;
1602         pipe->tb_credits -= pkt_len;
1603         pipe->tc_credits[tc_index] -= pkt_len;
1604
1605         return 1;
1606 }
1607
1608 #else
1609
1610 static inline int
1611 grinder_credits_check(struct rte_sched_port *port, uint32_t pos)
1612 {
1613         struct rte_sched_grinder *grinder = port->grinder + pos;
1614         struct rte_sched_subport *subport = grinder->subport;
1615         struct rte_sched_pipe *pipe = grinder->pipe;
1616         struct rte_mbuf *pkt = grinder->pkt;
1617         uint32_t tc_index = grinder->tc_index;
1618         uint32_t pkt_len = pkt->pkt.pkt_len + port->frame_overhead;
1619         uint32_t subport_tb_credits = subport->tb_credits;
1620         uint32_t subport_tc_credits = subport->tc_credits[tc_index];
1621         uint32_t pipe_tb_credits = pipe->tb_credits;
1622         uint32_t pipe_tc_credits = pipe->tc_credits[tc_index];
1623         uint32_t pipe_tc_ov_mask1[] = {UINT32_MAX, UINT32_MAX, UINT32_MAX, pipe->tc_ov_credits};
1624         uint32_t pipe_tc_ov_mask2[] = {0, 0, 0, UINT32_MAX};
1625         uint32_t pipe_tc_ov_credits = pipe_tc_ov_mask1[tc_index];
1626         int enough_credits;
1627         
1628         /* Check pipe and subport credits */
1629         enough_credits = (pkt_len <= subport_tb_credits) &&
1630                 (pkt_len <= subport_tc_credits) &&
1631                 (pkt_len <= pipe_tb_credits) &&
1632                 (pkt_len <= pipe_tc_credits) &&
1633                 (pkt_len <= pipe_tc_ov_credits);
1634         
1635         if (!enough_credits) {
1636                 return 0;
1637         }
1638         
1639         /* Update pipe and subport credits */
1640         subport->tb_credits -= pkt_len;
1641         subport->tc_credits[tc_index] -= pkt_len;
1642         pipe->tb_credits -= pkt_len;
1643         pipe->tc_credits[tc_index] -= pkt_len;
1644         pipe->tc_ov_credits -= pipe_tc_ov_mask2[tc_index] & pkt_len;
1645         
1646         return 1;
1647 }
1648
1649 #endif /* RTE_SCHED_SUBPORT_TC_OV */
1650
1651 static inline int 
1652 grinder_schedule(struct rte_sched_port *port, uint32_t pos)
1653 {
1654         struct rte_sched_grinder *grinder = port->grinder + pos;
1655         struct rte_sched_queue *queue = grinder->queue[grinder->qpos];
1656         struct rte_mbuf *pkt = grinder->pkt;
1657         uint32_t pkt_len = pkt->pkt.pkt_len + port->frame_overhead;
1658
1659 #if RTE_SCHED_TS_CREDITS_CHECK
1660         if (!grinder_credits_check(port, pos)) {
1661                 return 0;
1662         }
1663 #endif
1664
1665         /* Advance port time */
1666         port->time += pkt_len;
1667         
1668         /* Send packet */
1669         port->pkts_out[port->n_pkts_out ++] = pkt;
1670         queue->qr ++;
1671         grinder->wrr_tokens[grinder->qpos] += pkt_len * grinder->wrr_cost[grinder->qpos];
1672         if (queue->qr == queue->qw) {
1673                 uint32_t qindex = grinder->qindex[grinder->qpos];
1674
1675                 rte_bitmap_clear(port->bmp, qindex);
1676                 grinder->qmask &= ~(1 << grinder->qpos);
1677                 grinder->wrr_mask[grinder->qpos] = 0;
1678                 rte_sched_port_set_queue_empty_timestamp(port, qindex);
1679         }
1680         
1681         /* Reset pipe loop detection */
1682         port->pipe_loop = RTE_SCHED_PIPE_INVALID;
1683         grinder->productive = 1;
1684         
1685         return 1;
1686 }
1687
1688 #if RTE_SCHED_OPTIMIZATIONS
1689
1690 static inline int
1691 grinder_pipe_exists(struct rte_sched_port *port, uint32_t base_pipe)
1692 {
1693         __m128i index = _mm_set1_epi32 (base_pipe);
1694         __m128i pipes = _mm_load_si128((__m128i *)port->grinder_base_bmp_pos);
1695         __m128i res = _mm_cmpeq_epi32(pipes, index);
1696         pipes = _mm_load_si128((__m128i *)(port->grinder_base_bmp_pos + 4));
1697         pipes = _mm_cmpeq_epi32(pipes, index);
1698         res = _mm_or_si128(res, pipes);
1699
1700         if (_mm_testz_si128(res, res))
1701                 return 0;
1702
1703         return 1;
1704 }
1705
1706 #else
1707
1708 static inline int
1709 grinder_pipe_exists(struct rte_sched_port *port, uint32_t base_pipe)
1710 {
1711         uint32_t i;
1712         
1713         for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i ++) {
1714                 if (port->grinder_base_bmp_pos[i] == base_pipe) {
1715                         return 1;
1716                 }
1717         }
1718         
1719         return 0;
1720 }
1721
1722 #endif /* RTE_SCHED_OPTIMIZATIONS */
1723
1724 static inline void
1725 grinder_pcache_populate(struct rte_sched_port *port, uint32_t pos, uint32_t bmp_pos, uint64_t bmp_slab)
1726 {
1727         struct rte_sched_grinder *grinder = port->grinder + pos;
1728         uint16_t w[4];
1729
1730         grinder->pcache_w = 0;
1731         grinder->pcache_r = 0;
1732         
1733         w[0] = (uint16_t) bmp_slab;
1734         w[1] = (uint16_t) (bmp_slab >> 16);
1735         w[2] = (uint16_t) (bmp_slab >> 32);
1736         w[3] = (uint16_t) (bmp_slab >> 48);
1737         
1738         grinder->pcache_qmask[grinder->pcache_w] = w[0];
1739         grinder->pcache_qindex[grinder->pcache_w] = bmp_pos;
1740         grinder->pcache_w += (w[0] != 0);
1741         
1742         grinder->pcache_qmask[grinder->pcache_w] = w[1];
1743         grinder->pcache_qindex[grinder->pcache_w] = bmp_pos + 16;
1744         grinder->pcache_w += (w[1] != 0);
1745         
1746         grinder->pcache_qmask[grinder->pcache_w] = w[2];
1747         grinder->pcache_qindex[grinder->pcache_w] = bmp_pos + 32;
1748         grinder->pcache_w += (w[2] != 0);
1749         
1750         grinder->pcache_qmask[grinder->pcache_w] = w[3];
1751         grinder->pcache_qindex[grinder->pcache_w] = bmp_pos + 48;
1752         grinder->pcache_w += (w[3] != 0);
1753 }
1754
1755 static inline void
1756 grinder_tccache_populate(struct rte_sched_port *port, uint32_t pos, uint32_t qindex, uint16_t qmask)
1757 {
1758         struct rte_sched_grinder *grinder = port->grinder + pos;
1759         uint8_t b[4];
1760         
1761         grinder->tccache_w = 0;
1762         grinder->tccache_r = 0;
1763         
1764         b[0] = (uint8_t) (qmask & 0xF);
1765         b[1] = (uint8_t) ((qmask >> 4) & 0xF);
1766         b[2] = (uint8_t) ((qmask >> 8) & 0xF);
1767         b[3] = (uint8_t) ((qmask >> 12) & 0xF);
1768         
1769         grinder->tccache_qmask[grinder->tccache_w] = b[0];
1770         grinder->tccache_qindex[grinder->tccache_w] = qindex;
1771         grinder->tccache_w += (b[0] != 0);
1772         
1773         grinder->tccache_qmask[grinder->tccache_w] = b[1];
1774         grinder->tccache_qindex[grinder->tccache_w] = qindex + 4;
1775         grinder->tccache_w += (b[1] != 0);
1776         
1777         grinder->tccache_qmask[grinder->tccache_w] = b[2];
1778         grinder->tccache_qindex[grinder->tccache_w] = qindex + 8;
1779         grinder->tccache_w += (b[2] != 0);
1780         
1781         grinder->tccache_qmask[grinder->tccache_w] = b[3];
1782         grinder->tccache_qindex[grinder->tccache_w] = qindex + 12;
1783         grinder->tccache_w += (b[3] != 0);
1784 }
1785
1786 static inline int
1787 grinder_next_tc(struct rte_sched_port *port, uint32_t pos)
1788 {
1789         struct rte_sched_grinder *grinder = port->grinder + pos;
1790         struct rte_mbuf **qbase;
1791         uint32_t qindex; 
1792         uint16_t qsize; 
1793
1794         if (grinder->tccache_r == grinder->tccache_w) {
1795                 return 0;
1796         }
1797
1798         qindex = grinder->tccache_qindex[grinder->tccache_r];
1799         qbase = rte_sched_port_qbase(port, qindex);
1800         qsize = rte_sched_port_qsize(port, qindex);
1801
1802         grinder->tc_index = (qindex >> 2) & 0x3;
1803         grinder->qmask = grinder->tccache_qmask[grinder->tccache_r];
1804         grinder->qsize = qsize;
1805         
1806         grinder->qindex[0] = qindex;
1807         grinder->qindex[1] = qindex + 1;
1808         grinder->qindex[2] = qindex + 2;
1809         grinder->qindex[3] = qindex + 3;
1810
1811         grinder->queue[0] = port->queue + qindex;
1812         grinder->queue[1] = port->queue + qindex + 1;
1813         grinder->queue[2] = port->queue + qindex + 2;
1814         grinder->queue[3] = port->queue + qindex + 3;
1815
1816         grinder->qbase[0] = qbase;
1817         grinder->qbase[1] = qbase + qsize;
1818         grinder->qbase[2] = qbase + 2 * qsize;
1819         grinder->qbase[3] = qbase + 3 * qsize;
1820         
1821         grinder->tccache_r ++;
1822         return 1;
1823 }
1824
1825 static inline int
1826 grinder_next_pipe(struct rte_sched_port *port, uint32_t pos)
1827 {
1828         struct rte_sched_grinder *grinder = port->grinder + pos;
1829         uint32_t pipe_qindex;
1830         uint16_t pipe_qmask;
1831
1832         if (grinder->pcache_r < grinder->pcache_w) {
1833                 pipe_qmask = grinder->pcache_qmask[grinder->pcache_r];
1834                 pipe_qindex = grinder->pcache_qindex[grinder->pcache_r];
1835                 grinder->pcache_r ++;
1836         } else {
1837                 uint64_t bmp_slab = 0;
1838                 uint32_t bmp_pos = 0;
1839                 
1840                 /* Get another non-empty pipe group */          
1841                 if (unlikely(rte_bitmap_scan(port->bmp, &bmp_pos, &bmp_slab) <= 0)) {
1842                         return 0;
1843                 }
1844                 
1845 #if RTE_SCHED_DEBUG
1846                 debug_check_queue_slab(port, bmp_pos, bmp_slab);
1847 #endif  
1848
1849                 /* Return if pipe group already in one of the other grinders */
1850                 port->grinder_base_bmp_pos[pos] = RTE_SCHED_BMP_POS_INVALID;
1851                 if (unlikely(grinder_pipe_exists(port, bmp_pos))) {
1852                         return 0;
1853                 }
1854                 port->grinder_base_bmp_pos[pos] = bmp_pos;
1855                 
1856                 /* Install new pipe group into grinder's pipe cache */
1857                 grinder_pcache_populate(port, pos, bmp_pos, bmp_slab);
1858
1859                 pipe_qmask = grinder->pcache_qmask[0];
1860                 pipe_qindex = grinder->pcache_qindex[0];
1861                 grinder->pcache_r = 1;
1862         }
1863         
1864         /* Install new pipe in the grinder */
1865         grinder->pindex = pipe_qindex >> 4;
1866         grinder->subport = port->subport + (grinder->pindex / port->n_pipes_per_subport);
1867         grinder->pipe = port->pipe + grinder->pindex;
1868         grinder->pipe_params = NULL; /* to be set after the pipe structure is prefetched */
1869         grinder->productive = 0;
1870
1871         grinder_tccache_populate(port, pos, pipe_qindex, pipe_qmask);
1872         grinder_next_tc(port, pos);
1873         
1874         /* Check for pipe exhaustion */
1875         if (grinder->pindex == port->pipe_loop) {
1876                 port->pipe_exhaustion = 1;
1877                 port->pipe_loop = RTE_SCHED_PIPE_INVALID;
1878         }
1879         
1880         return 1;       
1881 }
1882
1883 #if RTE_SCHED_WRR == 0
1884
1885 #define grinder_wrr_load(a,b)
1886
1887 #define grinder_wrr_store(a,b)
1888
1889 static inline void
1890 grinder_wrr(struct rte_sched_port *port, uint32_t pos)
1891 {
1892         struct rte_sched_grinder *grinder = port->grinder + pos;
1893         uint64_t slab = grinder->qmask;
1894         
1895         if (rte_bsf64(slab, &grinder->qpos) == 0) {
1896                 rte_panic("grinder wrr\n");
1897         }
1898 }
1899
1900 #elif RTE_SCHED_WRR == 1
1901
1902 static inline void
1903 grinder_wrr_load(struct rte_sched_port *port, uint32_t pos)
1904 {
1905         struct rte_sched_grinder *grinder = port->grinder + pos;
1906         struct rte_sched_pipe *pipe = grinder->pipe;
1907         struct rte_sched_pipe_profile *pipe_params = grinder->pipe_params;
1908         uint32_t tc_index = grinder->tc_index;
1909         uint32_t qmask = grinder->qmask;
1910         uint32_t qindex;
1911         
1912         qindex = tc_index * 4;
1913         
1914         grinder->wrr_tokens[0] = ((uint16_t) pipe->wrr_tokens[qindex]) << RTE_SCHED_WRR_SHIFT;
1915         grinder->wrr_tokens[1] = ((uint16_t) pipe->wrr_tokens[qindex + 1]) << RTE_SCHED_WRR_SHIFT;
1916         grinder->wrr_tokens[2] = ((uint16_t) pipe->wrr_tokens[qindex + 2]) << RTE_SCHED_WRR_SHIFT;
1917         grinder->wrr_tokens[3] = ((uint16_t) pipe->wrr_tokens[qindex + 3]) << RTE_SCHED_WRR_SHIFT;
1918         
1919         grinder->wrr_mask[0] = (qmask & 0x1) * 0xFFFF;
1920         grinder->wrr_mask[1] = ((qmask >> 1) & 0x1) * 0xFFFF;
1921         grinder->wrr_mask[2] = ((qmask >> 2) & 0x1) * 0xFFFF;
1922         grinder->wrr_mask[3] = ((qmask >> 3) & 0x1) * 0xFFFF;
1923         
1924         grinder->wrr_cost[0] = pipe_params->wrr_cost[qindex];
1925         grinder->wrr_cost[1] = pipe_params->wrr_cost[qindex + 1];
1926         grinder->wrr_cost[2] = pipe_params->wrr_cost[qindex + 2];
1927         grinder->wrr_cost[3] = pipe_params->wrr_cost[qindex + 3];
1928 }
1929
1930 static inline void
1931 grinder_wrr_store(struct rte_sched_port *port, uint32_t pos)
1932 {
1933         struct rte_sched_grinder *grinder = port->grinder + pos;
1934         struct rte_sched_pipe *pipe = grinder->pipe;
1935         uint32_t tc_index = grinder->tc_index;
1936         uint32_t qindex;
1937         
1938         qindex = tc_index * 4;
1939         
1940         pipe->wrr_tokens[qindex] = (uint8_t) ((grinder->wrr_tokens[0] & grinder->wrr_mask[0]) >> RTE_SCHED_WRR_SHIFT);
1941         pipe->wrr_tokens[qindex + 1] = (uint8_t) ((grinder->wrr_tokens[1] & grinder->wrr_mask[1]) >> RTE_SCHED_WRR_SHIFT);
1942         pipe->wrr_tokens[qindex + 2] = (uint8_t) ((grinder->wrr_tokens[2] & grinder->wrr_mask[2]) >> RTE_SCHED_WRR_SHIFT);
1943         pipe->wrr_tokens[qindex + 3] = (uint8_t) ((grinder->wrr_tokens[3] & grinder->wrr_mask[3]) >> RTE_SCHED_WRR_SHIFT);
1944 }
1945
1946 static inline void
1947 grinder_wrr(struct rte_sched_port *port, uint32_t pos)
1948 {
1949         struct rte_sched_grinder *grinder = port->grinder + pos;
1950         uint16_t wrr_tokens_min;
1951
1952         grinder->wrr_tokens[0] |= ~grinder->wrr_mask[0];
1953         grinder->wrr_tokens[1] |= ~grinder->wrr_mask[1];
1954         grinder->wrr_tokens[2] |= ~grinder->wrr_mask[2];
1955         grinder->wrr_tokens[3] |= ~grinder->wrr_mask[3];
1956         
1957         grinder->qpos = rte_min_pos_4_u16(grinder->wrr_tokens);
1958         wrr_tokens_min = grinder->wrr_tokens[grinder->qpos];
1959         
1960         grinder->wrr_tokens[0] -= wrr_tokens_min;
1961         grinder->wrr_tokens[1] -= wrr_tokens_min;
1962         grinder->wrr_tokens[2] -= wrr_tokens_min;
1963         grinder->wrr_tokens[3] -= wrr_tokens_min;
1964 }
1965
1966 #else
1967
1968 #error Invalid value for RTE_SCHED_WRR
1969
1970 #endif /* RTE_SCHED_WRR */
1971
1972 #define grinder_evict(port, pos)
1973
1974 static inline void
1975 grinder_prefetch_pipe(struct rte_sched_port *port, uint32_t pos)
1976 {
1977         struct rte_sched_grinder *grinder = port->grinder + pos;
1978         
1979         rte_prefetch0(grinder->pipe);
1980         rte_prefetch0(grinder->queue[0]);
1981 }
1982
1983 static inline void
1984 grinder_prefetch_tc_queue_arrays(struct rte_sched_port *port, uint32_t pos)
1985 {
1986         struct rte_sched_grinder *grinder = port->grinder + pos;
1987         uint16_t qsize, qr[4];
1988         
1989         qsize = grinder->qsize;
1990         qr[0] = grinder->queue[0]->qr & (qsize - 1);
1991         qr[1] = grinder->queue[1]->qr & (qsize - 1);
1992         qr[2] = grinder->queue[2]->qr & (qsize - 1);
1993         qr[3] = grinder->queue[3]->qr & (qsize - 1);
1994         
1995         rte_prefetch0(grinder->qbase[0] + qr[0]);
1996         rte_prefetch0(grinder->qbase[1] + qr[1]);
1997
1998         grinder_wrr_load(port, pos);
1999         grinder_wrr(port, pos);
2000         
2001         rte_prefetch0(grinder->qbase[2] + qr[2]);
2002         rte_prefetch0(grinder->qbase[3] + qr[3]);       
2003 }
2004
2005 static inline void
2006 grinder_prefetch_mbuf(struct rte_sched_port *port, uint32_t pos)
2007 {
2008         struct rte_sched_grinder *grinder = port->grinder + pos;
2009         uint32_t qpos = grinder->qpos;
2010         struct rte_mbuf **qbase = grinder->qbase[qpos];
2011         uint16_t qsize = grinder->qsize;
2012         uint16_t qr = grinder->queue[qpos]->qr & (qsize - 1);
2013         
2014         grinder->pkt = qbase[qr];
2015         rte_prefetch0(grinder->pkt);
2016         
2017         if (unlikely((qr & 0x7) == 7)) {
2018                 uint16_t qr_next = (grinder->queue[qpos]->qr + 1) & (qsize - 1);
2019                 
2020                 rte_prefetch0(qbase + qr_next);
2021         }
2022 }
2023
2024 static inline uint32_t
2025 grinder_handle(struct rte_sched_port *port, uint32_t pos)
2026 {
2027         struct rte_sched_grinder *grinder = port->grinder + pos;
2028         
2029         switch (grinder->state) {
2030         case e_GRINDER_PREFETCH_PIPE:
2031         {
2032                 if (grinder_next_pipe(port, pos)) {
2033                         grinder_prefetch_pipe(port, pos);
2034                         port->busy_grinders ++;
2035                         
2036                         grinder->state = e_GRINDER_PREFETCH_TC_QUEUE_ARRAYS;
2037                         return 0;
2038                 }
2039                 
2040                 return 0;
2041         }
2042
2043         case e_GRINDER_PREFETCH_TC_QUEUE_ARRAYS:
2044         {
2045                 struct rte_sched_pipe *pipe = grinder->pipe;
2046                 
2047                 grinder->pipe_params = port->pipe_profiles + pipe->profile;
2048                 grinder_prefetch_tc_queue_arrays(port, pos);
2049                 grinder_credits_update(port, pos);
2050                 
2051                 grinder->state = e_GRINDER_PREFETCH_MBUF;
2052                 return 0;
2053         }
2054         
2055         case e_GRINDER_PREFETCH_MBUF:
2056         {
2057                 grinder_prefetch_mbuf(port, pos);
2058                 
2059                 grinder->state = e_GRINDER_READ_MBUF;
2060                 return 0;
2061         }
2062         
2063         case e_GRINDER_READ_MBUF:
2064         {
2065                 uint32_t result = 0;
2066                 
2067                 result = grinder_schedule(port, pos);
2068                 
2069                 /* Look for next packet within the same TC */
2070                 if (result && grinder->qmask) {
2071                         grinder_wrr(port, pos);
2072                         grinder_prefetch_mbuf(port, pos);
2073                         
2074                         return 1;
2075                 }
2076                 grinder_wrr_store(port, pos);
2077                 
2078                 /* Look for another active TC within same pipe */
2079                 if (grinder_next_tc(port, pos)) {
2080                         grinder_prefetch_tc_queue_arrays(port, pos);
2081                         
2082                         grinder->state = e_GRINDER_PREFETCH_MBUF;
2083                         return result;
2084                 }               
2085                 if ((grinder->productive == 0) && (port->pipe_loop == RTE_SCHED_PIPE_INVALID)) {
2086                         port->pipe_loop = grinder->pindex;
2087                 }
2088                 grinder_evict(port, pos);
2089                 
2090                 /* Look for another active pipe */
2091                 if (grinder_next_pipe(port, pos)) {
2092                         grinder_prefetch_pipe(port, pos);
2093                         
2094                         grinder->state = e_GRINDER_PREFETCH_TC_QUEUE_ARRAYS;
2095                         return result;
2096                 }
2097                 
2098                 /* No active pipe found */
2099                 port->busy_grinders --;
2100                 
2101                 grinder->state = e_GRINDER_PREFETCH_PIPE;
2102                 return result;
2103         }
2104         
2105         default:
2106                 rte_panic("Algorithmic error (invalid state)\n");
2107                 return 0;
2108         }
2109 }
2110
2111 static inline void 
2112 rte_sched_port_time_resync(struct rte_sched_port *port)
2113 {
2114         uint64_t cycles = rte_get_tsc_cycles();
2115         uint64_t cycles_diff = cycles - port->time_cpu_cycles;
2116         double bytes_diff = ((double) cycles_diff) / port->cycles_per_byte;
2117         
2118         /* Advance port time */
2119         port->time_cpu_cycles = cycles;
2120         port->time_cpu_bytes += (uint64_t) bytes_diff;
2121         if (port->time < port->time_cpu_bytes) {
2122                 port->time = port->time_cpu_bytes;
2123         }
2124
2125         /* Reset pipe loop detection */
2126         port->pipe_loop = RTE_SCHED_PIPE_INVALID;
2127 }
2128
2129 static inline int
2130 rte_sched_port_exceptions(struct rte_sched_port *port)
2131 {
2132         int exceptions;
2133
2134         /* Check if any exception flag is set */
2135         exceptions = (port->busy_grinders == 0) ||
2136                 (port->pipe_exhaustion == 1);
2137         
2138         /* Clear exception flags */
2139         port->pipe_exhaustion = 0;
2140         
2141         return exceptions;
2142 }
2143
2144 int
2145 rte_sched_port_dequeue(struct rte_sched_port *port, struct rte_mbuf **pkts, uint32_t n_pkts)
2146 {
2147         uint32_t i, count;
2148         
2149         port->pkts_out = pkts;
2150         port->n_pkts_out = 0;
2151         
2152         rte_sched_port_time_resync(port);
2153         
2154         /* Take each queue in the grinder one step further */
2155         for (i = 0, count = 0; ; i ++)  {
2156                 count += grinder_handle(port, i & (RTE_SCHED_PORT_N_GRINDERS - 1));
2157                 if ((count == n_pkts) || rte_sched_port_exceptions(port)) {
2158                         break;
2159                 }
2160         }
2161         
2162         return count;
2163 }