Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <stdalign.h>
6 : : #include <string.h>
7 : : #include <sys/queue.h>
8 : :
9 : : #include <eal_export.h>
10 : : #include <rte_string_fns.h>
11 : : #include <rte_log.h>
12 : : #include <rte_mbuf.h>
13 : : #include <rte_mbuf_dyn.h>
14 : : #include <rte_eal_memconfig.h>
15 : : #include <rte_errno.h>
16 : : #include <rte_malloc.h>
17 : : #include <rte_tailq.h>
18 : :
19 : : #include "rte_reorder.h"
20 : :
21 [ - + ]: 252 : RTE_LOG_REGISTER_DEFAULT(reorder_logtype, INFO);
22 : : #define RTE_LOGTYPE_REORDER reorder_logtype
23 : : #define REORDER_LOG(level, ...) \
24 : : RTE_LOG_LINE(level, REORDER, "" __VA_ARGS__)
25 : :
26 : : TAILQ_HEAD(rte_reorder_list, rte_tailq_entry);
27 : :
28 : : static struct rte_tailq_elem rte_reorder_tailq = {
29 : : .name = "RTE_REORDER",
30 : : };
31 [ - + ]: 252 : EAL_REGISTER_TAILQ(rte_reorder_tailq)
32 : :
33 : : #define NO_FLAGS 0
34 : : #define RTE_REORDER_PREFIX "RO_"
35 : : #define RTE_REORDER_NAMESIZE 32
36 : :
37 : : #define RTE_REORDER_SEQN_DYNFIELD_NAME "rte_reorder_seqn_dynfield"
38 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_reorder_seqn_dynfield_offset, 20.11)
39 : : int rte_reorder_seqn_dynfield_offset = -1;
40 : :
41 : : /* A generic circular buffer */
42 : : struct __rte_cache_aligned cir_buffer {
43 : : unsigned int size; /**< Number of entries that can be stored */
44 : : unsigned int mask; /**< [buffer_size - 1]: used for wrap-around */
45 : : unsigned int head; /**< insertion point in buffer */
46 : : unsigned int tail; /**< extraction point in buffer */
47 : : struct rte_mbuf **entries;
48 : : };
49 : :
50 : : /* The reorder buffer data structure itself */
51 : : struct __rte_cache_aligned rte_reorder_buffer {
52 : : char name[RTE_REORDER_NAMESIZE];
53 : : uint32_t min_seqn; /**< Lowest seq. number that can be in the buffer */
54 : : unsigned int memsize; /**< memory area size of reorder buffer */
55 : : bool is_initialized; /**< flag indicates that buffer was initialized */
56 : :
57 : : struct cir_buffer ready_buf; /**< temp buffer for dequeued entries */
58 : : struct cir_buffer order_buf; /**< buffer used to reorder entries */
59 : : };
60 : :
61 : : static void
62 : : rte_reorder_free_mbufs(struct rte_reorder_buffer *b);
63 : :
64 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_reorder_memory_footprint_get, 23.07)
65 : : unsigned int
66 : 22 : rte_reorder_memory_footprint_get(unsigned int size)
67 : : {
68 : 22 : return sizeof(struct rte_reorder_buffer) + (2 * size * sizeof(struct rte_mbuf *));
69 : : }
70 : :
71 : : RTE_EXPORT_SYMBOL(rte_reorder_init)
72 : : struct rte_reorder_buffer *
73 : 11 : rte_reorder_init(struct rte_reorder_buffer *b, unsigned int bufsize,
74 : : const char *name, unsigned int size)
75 : : {
76 : 11 : const unsigned int min_bufsize = rte_reorder_memory_footprint_get(size);
77 : : static const struct rte_mbuf_dynfield reorder_seqn_dynfield_desc = {
78 : : .name = RTE_REORDER_SEQN_DYNFIELD_NAME,
79 : : .size = sizeof(rte_reorder_seqn_t),
80 : : .align = alignof(rte_reorder_seqn_t),
81 : : };
82 : :
83 [ + + ]: 11 : if (b == NULL) {
84 : 2 : REORDER_LOG(ERR, "Invalid reorder buffer parameter:"
85 : : " NULL");
86 : 2 : rte_errno = EINVAL;
87 : 2 : return NULL;
88 : : }
89 : : if (!rte_is_power_of_2(size)) {
90 : 1 : REORDER_LOG(ERR, "Invalid reorder buffer size"
91 : : " - Not a power of 2");
92 : 1 : rte_errno = EINVAL;
93 : 1 : return NULL;
94 : : }
95 [ - + ]: 8 : if (name == NULL) {
96 : 0 : REORDER_LOG(ERR, "Invalid reorder buffer name ptr:"
97 : : " NULL");
98 : 0 : rte_errno = EINVAL;
99 : 0 : return NULL;
100 : : }
101 [ + + ]: 8 : if (bufsize < min_bufsize) {
102 : 1 : REORDER_LOG(ERR, "Invalid reorder buffer memory size: %u, "
103 : : "minimum required: %u", bufsize, min_bufsize);
104 : 1 : rte_errno = EINVAL;
105 : 1 : return NULL;
106 : : }
107 : :
108 : 7 : rte_reorder_seqn_dynfield_offset = rte_mbuf_dynfield_register(&reorder_seqn_dynfield_desc);
109 [ - + ]: 7 : if (rte_reorder_seqn_dynfield_offset < 0) {
110 : 0 : REORDER_LOG(ERR,
111 : : "Failed to register mbuf field for reorder sequence number, rte_errno: %i",
112 : : rte_errno);
113 : 0 : rte_errno = ENOMEM;
114 : 0 : return NULL;
115 : : }
116 : :
117 : 7 : memset(b, 0, bufsize);
118 : 7 : strlcpy(b->name, name, sizeof(b->name));
119 : 7 : b->memsize = bufsize;
120 : 7 : b->order_buf.size = b->ready_buf.size = size;
121 : 7 : b->order_buf.mask = b->ready_buf.mask = size - 1;
122 : 7 : b->ready_buf.entries = (void *)&b[1];
123 : 7 : b->order_buf.entries = RTE_PTR_ADD(&b[1],
124 : : size * sizeof(b->ready_buf.entries[0]));
125 : :
126 : 7 : return b;
127 : : }
128 : :
129 : : /*
130 : : * Insert new entry into global list.
131 : : * Returns pointer to already inserted entry if such exists, or to newly inserted one.
132 : : */
133 : : static struct rte_tailq_entry *
134 : 7 : rte_reorder_entry_insert(struct rte_tailq_entry *new_te)
135 : : {
136 : : struct rte_reorder_list *reorder_list;
137 : : struct rte_reorder_buffer *b, *nb;
138 : : struct rte_tailq_entry *te;
139 : :
140 : 7 : rte_mcfg_tailq_write_lock();
141 : :
142 : 7 : reorder_list = RTE_TAILQ_CAST(rte_reorder_tailq.head, rte_reorder_list);
143 : : /* guarantee there's no existing */
144 [ + + ]: 12 : TAILQ_FOREACH(te, reorder_list, next) {
145 : 6 : b = (struct rte_reorder_buffer *) te->data;
146 : 6 : nb = (struct rte_reorder_buffer *) new_te->data;
147 [ + + ]: 6 : if (strncmp(nb->name, b->name, RTE_REORDER_NAMESIZE) == 0)
148 : : break;
149 : : }
150 : :
151 [ + + ]: 7 : if (te == NULL) {
152 : 6 : TAILQ_INSERT_TAIL(reorder_list, new_te, next);
153 : : te = new_te;
154 : : }
155 : :
156 : 7 : rte_mcfg_tailq_write_unlock();
157 : :
158 : 7 : return te;
159 : : }
160 : :
161 : : RTE_EXPORT_SYMBOL(rte_reorder_create)
162 : : struct rte_reorder_buffer*
163 : 9 : rte_reorder_create(const char *name, unsigned socket_id, unsigned int size)
164 : : {
165 : : struct rte_reorder_buffer *b = NULL;
166 : : struct rte_tailq_entry *te, *te_inserted;
167 : :
168 : 9 : const unsigned int bufsize = rte_reorder_memory_footprint_get(size);
169 : :
170 : : /* Check user arguments. */
171 : : if (!rte_is_power_of_2(size)) {
172 : 1 : REORDER_LOG(ERR, "Invalid reorder buffer size"
173 : : " - Not a power of 2");
174 : 1 : rte_errno = EINVAL;
175 : 1 : return NULL;
176 : : }
177 [ + + ]: 8 : if (name == NULL) {
178 : 1 : REORDER_LOG(ERR, "Invalid reorder buffer name ptr:"
179 : : " NULL");
180 : 1 : rte_errno = EINVAL;
181 : 1 : return NULL;
182 : : }
183 : :
184 : : /* allocate tailq entry */
185 : 7 : te = rte_zmalloc("REORDER_TAILQ_ENTRY", sizeof(*te), 0);
186 [ - + ]: 7 : if (te == NULL) {
187 : 0 : REORDER_LOG(ERR, "Failed to allocate tailq entry");
188 : 0 : rte_errno = ENOMEM;
189 : 0 : return NULL;
190 : : }
191 : :
192 : : /* Allocate memory to store the reorder buffer structure. */
193 : 7 : b = rte_zmalloc_socket("REORDER_BUFFER", bufsize, 0, socket_id);
194 [ - + ]: 7 : if (b == NULL) {
195 : 0 : REORDER_LOG(ERR, "Memzone allocation failed");
196 : 0 : rte_errno = ENOMEM;
197 : 0 : rte_free(te);
198 : 0 : return NULL;
199 : : } else {
200 [ - + ]: 7 : if (rte_reorder_init(b, bufsize, name, size) == NULL) {
201 : 0 : rte_free(b);
202 : 0 : rte_free(te);
203 : 0 : return NULL;
204 : : }
205 : 7 : te->data = (void *)b;
206 : : }
207 : :
208 : 7 : te_inserted = rte_reorder_entry_insert(te);
209 [ + + ]: 7 : if (te_inserted != te) {
210 : 1 : rte_free(b);
211 : 1 : rte_free(te);
212 : 1 : return te_inserted->data;
213 : : }
214 : :
215 : : return b;
216 : : }
217 : :
218 : : RTE_EXPORT_SYMBOL(rte_reorder_reset)
219 : : void
220 : 0 : rte_reorder_reset(struct rte_reorder_buffer *b)
221 : : {
222 : : char name[RTE_REORDER_NAMESIZE];
223 : :
224 : 0 : rte_reorder_free_mbufs(b);
225 : 0 : strlcpy(name, b->name, sizeof(name));
226 : : /* No error checking as current values should be valid */
227 : 0 : rte_reorder_init(b, b->memsize, name, b->order_buf.size);
228 : 0 : }
229 : :
230 : : static void
231 : 6 : rte_reorder_free_mbufs(struct rte_reorder_buffer *b)
232 : : {
233 : : unsigned i;
234 : :
235 : : /* Free up the mbufs of order buffer & ready buffer */
236 [ + + ]: 16414 : for (i = 0; i < b->order_buf.size; i++) {
237 : 16408 : rte_pktmbuf_free(b->order_buf.entries[i]);
238 : 16408 : rte_pktmbuf_free(b->ready_buf.entries[i]);
239 : : }
240 : 6 : }
241 : :
242 : : RTE_EXPORT_SYMBOL(rte_reorder_free)
243 : : void
244 : 6 : rte_reorder_free(struct rte_reorder_buffer *b)
245 : : {
246 : : struct rte_reorder_list *reorder_list;
247 : : struct rte_tailq_entry *te;
248 : :
249 : : /* Check user arguments. */
250 [ + - ]: 6 : if (b == NULL)
251 : : return;
252 : :
253 : 6 : reorder_list = RTE_TAILQ_CAST(rte_reorder_tailq.head, rte_reorder_list);
254 : :
255 : 6 : rte_mcfg_tailq_write_lock();
256 : :
257 : : /* find our tailq entry */
258 [ + - ]: 11 : TAILQ_FOREACH(te, reorder_list, next) {
259 [ + + ]: 11 : if (te->data == (void *) b)
260 : : break;
261 : : }
262 [ - + ]: 6 : if (te == NULL) {
263 : 0 : rte_mcfg_tailq_write_unlock();
264 : 0 : return;
265 : : }
266 : :
267 [ - + ]: 6 : TAILQ_REMOVE(reorder_list, te, next);
268 : :
269 : 6 : rte_mcfg_tailq_write_unlock();
270 : :
271 : 6 : rte_reorder_free_mbufs(b);
272 : :
273 : 6 : rte_free(b);
274 : 6 : rte_free(te);
275 : : }
276 : :
277 : : RTE_EXPORT_SYMBOL(rte_reorder_find_existing)
278 : : struct rte_reorder_buffer *
279 : 4 : rte_reorder_find_existing(const char *name)
280 : : {
281 : : struct rte_reorder_buffer *b = NULL;
282 : : struct rte_tailq_entry *te;
283 : : struct rte_reorder_list *reorder_list;
284 : :
285 [ - + ]: 4 : if (name == NULL) {
286 : 0 : rte_errno = EINVAL;
287 : 0 : return NULL;
288 : : }
289 : :
290 : 4 : reorder_list = RTE_TAILQ_CAST(rte_reorder_tailq.head, rte_reorder_list);
291 : :
292 : 4 : rte_mcfg_tailq_read_lock();
293 [ + + ]: 7 : TAILQ_FOREACH(te, reorder_list, next) {
294 : 5 : b = (struct rte_reorder_buffer *) te->data;
295 [ + + ]: 5 : if (strncmp(name, b->name, RTE_REORDER_NAMESIZE) == 0)
296 : : break;
297 : : }
298 : 4 : rte_mcfg_tailq_read_unlock();
299 : :
300 [ + + ]: 4 : if (te == NULL) {
301 : 2 : rte_errno = ENOENT;
302 : 2 : return NULL;
303 : : }
304 : :
305 : : return b;
306 : : }
307 : :
308 : : static unsigned
309 : 4 : rte_reorder_fill_overflow(struct rte_reorder_buffer *b, unsigned n)
310 : : {
311 : : /*
312 : : * 1. Move all ready entries that fit to the ready_buf
313 : : * 2. check if we meet the minimum needed (n).
314 : : * 3. If not, then skip any gaps and keep moving.
315 : : * 4. If at any point the ready buffer is full, stop
316 : : * 5. Return the number of positions the order_buf head has moved
317 : : */
318 : :
319 : : struct cir_buffer *order_buf = &b->order_buf,
320 : : *ready_buf = &b->ready_buf;
321 : :
322 : : unsigned int order_head_adv = 0;
323 : :
324 : : /*
325 : : * move at least n packets to ready buffer, assuming ready buffer
326 : : * has room for those packets.
327 : : */
328 [ + + ]: 11 : while (order_head_adv < n &&
329 [ + + ]: 4 : ((ready_buf->head + 1) & ready_buf->mask) != ready_buf->tail) {
330 : :
331 : : /* if we are blocked waiting on a packet, skip it */
332 [ - + ]: 3 : if (order_buf->entries[order_buf->head] == NULL) {
333 : 0 : order_buf->head = (order_buf->head + 1) & order_buf->mask;
334 : 0 : order_head_adv++;
335 : : }
336 : :
337 : : /* Move all ready entries that fit to the ready_buf */
338 [ + + ]: 11 : while (order_buf->entries[order_buf->head] != NULL) {
339 : 9 : ready_buf->entries[ready_buf->head] =
340 : : order_buf->entries[order_buf->head];
341 : :
342 : 9 : order_buf->entries[order_buf->head] = NULL;
343 : 9 : order_head_adv++;
344 : :
345 : 9 : order_buf->head = (order_buf->head + 1) & order_buf->mask;
346 : :
347 [ + + ]: 9 : if (((ready_buf->head + 1) & ready_buf->mask) == ready_buf->tail)
348 : : break;
349 : :
350 : 8 : ready_buf->head = (ready_buf->head + 1) & ready_buf->mask;
351 : : }
352 : : }
353 : :
354 : 4 : b->min_seqn += order_head_adv;
355 : : /* Return the number of positions the order_buf head has moved */
356 : 4 : return order_head_adv;
357 : : }
358 : :
359 : : RTE_EXPORT_SYMBOL(rte_reorder_insert)
360 : : int
361 : 20 : rte_reorder_insert(struct rte_reorder_buffer *b, struct rte_mbuf *mbuf)
362 : : {
363 : : uint32_t offset, position;
364 : : struct cir_buffer *order_buf;
365 : :
366 [ - + ]: 20 : if (b == NULL || mbuf == NULL) {
367 : 0 : rte_errno = EINVAL;
368 : 0 : return -1;
369 : : }
370 : :
371 : : order_buf = &b->order_buf;
372 [ + + ]: 20 : if (!b->is_initialized) {
373 : 3 : b->min_seqn = *rte_reorder_seqn(mbuf);
374 : 3 : b->is_initialized = 1;
375 : : }
376 : :
377 : : /*
378 : : * calculate the offset from the head pointer we need to go.
379 : : * The subtraction takes care of the sequence number wrapping.
380 : : * For example (using 16-bit for brevity):
381 : : * min_seqn = 0xFFFD
382 : : * mbuf_seqn = 0x0010
383 : : * offset = 0x0010 - 0xFFFD = 0x13
384 : : */
385 : 20 : offset = *rte_reorder_seqn(mbuf) - b->min_seqn;
386 : :
387 : : /*
388 : : * action to take depends on offset.
389 : : * offset < buffer->size: the mbuf fits within the current window of
390 : : * sequence numbers we can reorder. EXPECTED CASE.
391 : : * offset > buffer->size: the mbuf is outside the current window. There
392 : : * are a number of cases to consider:
393 : : * 1. The packet sequence is just outside the window, then we need
394 : : * to see about shifting the head pointer and taking any ready
395 : : * to return packets out of the ring. If there was a delayed
396 : : * or dropped packet preventing drains from shifting the window
397 : : * this case will skip over the dropped packet instead, and any
398 : : * packets dequeued here will be returned on the next drain call.
399 : : * 2. The packet sequence number is vastly outside our window, taken
400 : : * here as having offset greater than twice the buffer size. In
401 : : * this case, the packet is probably an old or late packet that
402 : : * was previously skipped, so just enqueue the packet for
403 : : * immediate return on the next drain call, or else return error.
404 : : */
405 [ + + ]: 20 : if (offset < b->order_buf.size) {
406 : 14 : position = (order_buf->head + offset) & order_buf->mask;
407 : 14 : order_buf->entries[position] = mbuf;
408 [ + + ]: 6 : } else if (offset < 2 * b->order_buf.size) {
409 [ + + ]: 4 : if (rte_reorder_fill_overflow(b, offset + 1 - order_buf->size)
410 : : < (offset + 1 - order_buf->size)) {
411 : : /* Put in handling for enqueue straight to output */
412 : 1 : rte_errno = ENOSPC;
413 : 1 : return -1;
414 : : }
415 : 3 : offset = *rte_reorder_seqn(mbuf) - b->min_seqn;
416 : 3 : position = (order_buf->head + offset) & order_buf->mask;
417 : 3 : order_buf->entries[position] = mbuf;
418 : : } else {
419 : : /* Put in handling for enqueue straight to output */
420 : 2 : rte_errno = ERANGE;
421 : 2 : return -1;
422 : : }
423 : : return 0;
424 : : }
425 : :
426 : : RTE_EXPORT_SYMBOL(rte_reorder_drain)
427 : : unsigned int
428 : 4 : rte_reorder_drain(struct rte_reorder_buffer *b, struct rte_mbuf **mbufs,
429 : : unsigned max_mbufs)
430 : : {
431 : : unsigned int drain_cnt = 0;
432 : :
433 : : struct cir_buffer *order_buf = &b->order_buf,
434 : : *ready_buf = &b->ready_buf;
435 : :
436 : : /* Try to fetch requested number of mbufs from ready buffer */
437 [ - + + + ]: 7 : while ((drain_cnt < max_mbufs) && (ready_buf->tail != ready_buf->head)) {
438 : 3 : mbufs[drain_cnt++] = ready_buf->entries[ready_buf->tail];
439 : 3 : ready_buf->entries[ready_buf->tail] = NULL;
440 : 3 : ready_buf->tail = (ready_buf->tail + 1) & ready_buf->mask;
441 : : }
442 : :
443 : : /*
444 : : * If requested number of buffers not fetched from ready buffer, fetch
445 : : * remaining buffers from order buffer
446 : : */
447 [ + + ]: 5 : while ((drain_cnt < max_mbufs) &&
448 [ + + ]: 4 : (order_buf->entries[order_buf->head] != NULL)) {
449 : 1 : mbufs[drain_cnt++] = order_buf->entries[order_buf->head];
450 : 1 : order_buf->entries[order_buf->head] = NULL;
451 : 1 : b->min_seqn++;
452 : 1 : order_buf->head = (order_buf->head + 1) & order_buf->mask;
453 : : }
454 : :
455 : 4 : return drain_cnt;
456 : : }
457 : :
458 : : /* Binary search seqn in ready buffer */
459 : : static inline uint32_t
460 : 0 : ready_buffer_seqn_find(const struct cir_buffer *ready_buf, const uint32_t seqn)
461 : : {
462 : : uint32_t mid, value, position, high;
463 : : uint32_t low = 0;
464 : :
465 [ # # ]: 0 : if (ready_buf->tail > ready_buf->head)
466 : 0 : high = ready_buf->tail - ready_buf->head;
467 : : else
468 : 0 : high = ready_buf->head - ready_buf->tail;
469 : :
470 [ # # ]: 0 : while (low <= high) {
471 : 0 : mid = low + (high - low) / 2;
472 : 0 : position = (ready_buf->tail + mid) & ready_buf->mask;
473 [ # # ]: 0 : value = *rte_reorder_seqn(ready_buf->entries[position]);
474 [ # # ]: 0 : if (seqn == value)
475 : 0 : return mid;
476 [ # # ]: 0 : else if (seqn > value)
477 : 0 : low = mid + 1;
478 : : else
479 : 0 : high = mid - 1;
480 : : }
481 : :
482 : : return low;
483 : : }
484 : :
485 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_reorder_drain_up_to_seqn, 23.03)
486 : : unsigned int
487 : 2 : rte_reorder_drain_up_to_seqn(struct rte_reorder_buffer *b, struct rte_mbuf **mbufs,
488 : : const unsigned int max_mbufs, const rte_reorder_seqn_t seqn)
489 : : {
490 : : uint32_t i, position, offset;
491 : : unsigned int drain_cnt = 0;
492 : :
493 : : struct cir_buffer *order_buf = &b->order_buf,
494 : 2 : *ready_buf = &b->ready_buf;
495 : :
496 : : /* Seqn in Ready buffer */
497 [ - + ]: 2 : if (seqn < b->min_seqn) {
498 : : /* All sequence numbers are higher then given */
499 [ # # # # ]: 0 : if ((ready_buf->tail == ready_buf->head) ||
500 [ # # ]: 0 : (*rte_reorder_seqn(ready_buf->entries[ready_buf->tail]) > seqn))
501 : : return 0;
502 : :
503 : 0 : offset = ready_buffer_seqn_find(ready_buf, seqn);
504 : :
505 [ # # ]: 0 : for (i = 0; (i < offset) && (drain_cnt < max_mbufs); i++) {
506 : 0 : position = (ready_buf->tail + i) & ready_buf->mask;
507 : 0 : mbufs[drain_cnt++] = ready_buf->entries[position];
508 : 0 : ready_buf->entries[position] = NULL;
509 : : }
510 : 0 : ready_buf->tail = (ready_buf->tail + i) & ready_buf->mask;
511 : :
512 : 0 : return drain_cnt;
513 : : }
514 : :
515 : : /* Seqn in Order buffer, add all buffers from Ready buffer */
516 [ + - + + ]: 4 : while ((drain_cnt < max_mbufs) && (ready_buf->tail != ready_buf->head)) {
517 : 2 : mbufs[drain_cnt++] = ready_buf->entries[ready_buf->tail];
518 : 2 : ready_buf->entries[ready_buf->tail] = NULL;
519 : 2 : ready_buf->tail = (ready_buf->tail + 1) & ready_buf->mask;
520 : : }
521 : :
522 : : /* Fetch buffers from Order buffer up to given sequence number (exclusive) */
523 : 2 : offset = RTE_MIN(seqn - b->min_seqn, b->order_buf.size);
524 [ + + ]: 5 : for (i = 0; (i < offset) && (drain_cnt < max_mbufs); i++) {
525 : 3 : position = (order_buf->head + i) & order_buf->mask;
526 [ + + ]: 3 : if (order_buf->entries[position] == NULL)
527 : 1 : continue;
528 : 2 : mbufs[drain_cnt++] = order_buf->entries[position];
529 : 2 : order_buf->entries[position] = NULL;
530 : : }
531 : 2 : b->min_seqn += i;
532 : 2 : order_buf->head = (order_buf->head + i) & order_buf->mask;
533 : :
534 : 2 : return drain_cnt;
535 : : }
536 : :
537 : : static bool
538 : : rte_reorder_is_empty(const struct rte_reorder_buffer *b)
539 : : {
540 : : const struct cir_buffer *order_buf = &b->order_buf, *ready_buf = &b->ready_buf;
541 : : unsigned int i;
542 : :
543 : : /* Ready buffer does not have gaps */
544 : 2 : if (ready_buf->tail != ready_buf->head)
545 : : return false;
546 : :
547 : : /* Order buffer could have gaps, iterate */
548 [ + + ]: 6 : for (i = 0; i < order_buf->size; i++) {
549 [ + + ]: 5 : if (order_buf->entries[i] != NULL)
550 : : return false;
551 : : }
552 : :
553 : : return true;
554 : : }
555 : :
556 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_reorder_min_seqn_set, 23.03)
557 : : unsigned int
558 [ + - ]: 2 : rte_reorder_min_seqn_set(struct rte_reorder_buffer *b, rte_reorder_seqn_t min_seqn)
559 : : {
560 [ + + ]: 2 : if (!rte_reorder_is_empty(b))
561 : : return -ENOTEMPTY;
562 : :
563 : 1 : b->min_seqn = min_seqn;
564 : 1 : b->is_initialized = true;
565 : :
566 : 1 : return 0;
567 : : }
|