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