DPDK 26.11.0-rc2
rte_ring_elem_pvt.h
1/* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright (c) 2017,2018 HXT-semitech Corporation.
4 * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
5 * All rights reserved.
6 * Derived from FreeBSD's bufring.h
7 * Used as BSD-3 Licensed with permission from Kip Macy.
8 */
9
10#ifndef _RTE_RING_ELEM_PVT_H_
11#define _RTE_RING_ELEM_PVT_H_
12
13static __rte_always_inline void
14__rte_ring_enqueue_elems_32(void *ring_table, const void *obj_table,
15 uint32_t size, uint32_t idx, uint32_t n)
16{
17 unsigned int i;
18
19 uint32_t *ring = (uint32_t *)ring_table;
20 const uint32_t *obj = (const uint32_t *)obj_table;
21
22 if (likely(idx + n <= size)) {
23 for (i = 0; i < (n & ~0x7); i += 8, idx += 8) {
24 ring[idx] = obj[i];
25 ring[idx + 1] = obj[i + 1];
26 ring[idx + 2] = obj[i + 2];
27 ring[idx + 3] = obj[i + 3];
28 ring[idx + 4] = obj[i + 4];
29 ring[idx + 5] = obj[i + 5];
30 ring[idx + 6] = obj[i + 6];
31 ring[idx + 7] = obj[i + 7];
32 }
33 switch (n & 0x7) {
34 case 7:
35 ring[idx++] = obj[i++]; /* fallthrough */
36 case 6:
37 ring[idx++] = obj[i++]; /* fallthrough */
38 case 5:
39 ring[idx++] = obj[i++]; /* fallthrough */
40 case 4:
41 ring[idx++] = obj[i++]; /* fallthrough */
42 case 3:
43 ring[idx++] = obj[i++]; /* fallthrough */
44 case 2:
45 ring[idx++] = obj[i++]; /* fallthrough */
46 case 1:
47 ring[idx++] = obj[i++]; /* fallthrough */
48 }
49 } else {
50 for (i = 0; idx < size; i++, idx++)
51 ring[idx] = obj[i];
52 /* Start at the beginning */
53 for (idx = 0; i < n; i++, idx++)
54 ring[idx] = obj[i];
55 }
56}
57
58static __rte_always_inline void
59__rte_ring_enqueue_elems_64(void *ring_table, const void *obj_table,
60 uint32_t size, uint32_t idx, uint32_t n)
61{
62 unsigned int i;
63
64 uint64_t *ring = (uint64_t *)ring_table;
65 const unaligned_uint64_t *obj = (const unaligned_uint64_t *)obj_table;
66
67 if (likely(idx + n <= size)) {
68 for (i = 0; i < (n & ~0x3); i += 4, idx += 4) {
69 ring[idx] = obj[i];
70 ring[idx + 1] = obj[i + 1];
71 ring[idx + 2] = obj[i + 2];
72 ring[idx + 3] = obj[i + 3];
73 }
74 switch (n & 0x3) {
75 case 3:
76 ring[idx++] = obj[i++]; /* fallthrough */
77 case 2:
78 ring[idx++] = obj[i++]; /* fallthrough */
79 case 1:
80 ring[idx++] = obj[i++];
81 }
82 } else {
83 for (i = 0; idx < size; i++, idx++)
84 ring[idx] = obj[i];
85 /* Start at the beginning */
86 for (idx = 0; i < n; i++, idx++)
87 ring[idx] = obj[i];
88 }
89}
90
91static __rte_always_inline void
92__rte_ring_enqueue_elems_128(void *ring_table, const void *obj_table,
93 uint32_t size, uint32_t idx, uint32_t n)
94{
95 unsigned int i;
96
97 rte_int128_t *ring = (rte_int128_t *)ring_table;
98 const rte_int128_t *obj = (const rte_int128_t *)obj_table;
99
100 if (likely(idx + n <= size)) {
101 for (i = 0; i < (n & ~0x1); i += 2, idx += 2)
102 memcpy((void *)(ring + idx),
103 (const void *)(obj + i), 32);
104 switch (n & 0x1) {
105 case 1:
106 memcpy((void *)(ring + idx),
107 (const void *)(obj + i), 16);
108 }
109 } else {
110 for (i = 0; idx < size; i++, idx++)
111 memcpy((void *)(ring + idx),
112 (const void *)(obj + i), 16);
113 /* Start at the beginning */
114 for (idx = 0; i < n; i++, idx++)
115 memcpy((void *)(ring + idx),
116 (const void *)(obj + i), 16);
117 }
118}
119
120/* the actual enqueue of elements on the ring.
121 * Placed here since identical code needed in both
122 * single and multi producer enqueue functions.
123 */
124static __rte_always_inline void
125__rte_ring_do_enqueue_elems(void *ring_table, const void *obj_table,
126 uint32_t size, uint32_t idx, uint32_t esize, uint32_t num)
127{
128 /* 8B and 16B copies implemented individually to retain
129 * the current performance.
130 */
131 if (esize == 8)
132 __rte_ring_enqueue_elems_64(ring_table, obj_table, size,
133 idx, num);
134 else if (esize == 16)
135 __rte_ring_enqueue_elems_128(ring_table, obj_table, size,
136 idx, num);
137 else {
138 uint32_t scale, nr_idx, nr_num, nr_size;
139
140 /* Normalize to uint32_t */
141 scale = esize / sizeof(uint32_t);
142 nr_num = num * scale;
143 nr_idx = idx * scale;
144 nr_size = size * scale;
145 __rte_ring_enqueue_elems_32(ring_table, obj_table, nr_size,
146 nr_idx, nr_num);
147 }
148}
149
150static __rte_always_inline void
151__rte_ring_enqueue_elems(struct rte_ring *r, uint32_t prod_head,
152 const void *obj_table, uint32_t esize, uint32_t num)
153{
154 __rte_ring_do_enqueue_elems(&r[1], obj_table, r->size,
155 prod_head & r->mask, esize, num);
156}
157
158static __rte_always_inline void
159__rte_ring_dequeue_elems_32(void *obj_table, const void *ring_table,
160 uint32_t size, uint32_t idx, uint32_t n)
161{
162 unsigned int i;
163 uint32_t *obj = (uint32_t *)obj_table;
164 const uint32_t *ring = (const uint32_t *)ring_table;
165
166 if (likely(idx + n <= size)) {
167 for (i = 0; i < (n & ~0x7); i += 8, idx += 8) {
168 obj[i] = ring[idx];
169 obj[i + 1] = ring[idx + 1];
170 obj[i + 2] = ring[idx + 2];
171 obj[i + 3] = ring[idx + 3];
172 obj[i + 4] = ring[idx + 4];
173 obj[i + 5] = ring[idx + 5];
174 obj[i + 6] = ring[idx + 6];
175 obj[i + 7] = ring[idx + 7];
176 }
177 switch (n & 0x7) {
178 case 7:
179 obj[i++] = ring[idx++]; /* fallthrough */
180 case 6:
181 obj[i++] = ring[idx++]; /* fallthrough */
182 case 5:
183 obj[i++] = ring[idx++]; /* fallthrough */
184 case 4:
185 obj[i++] = ring[idx++]; /* fallthrough */
186 case 3:
187 obj[i++] = ring[idx++]; /* fallthrough */
188 case 2:
189 obj[i++] = ring[idx++]; /* fallthrough */
190 case 1:
191 obj[i++] = ring[idx++]; /* fallthrough */
192 }
193 } else {
194 for (i = 0; idx < size; i++, idx++)
195 obj[i] = ring[idx];
196 /* Start at the beginning */
197 for (idx = 0; i < n; i++, idx++)
198 obj[i] = ring[idx];
199 }
200}
201
202static __rte_always_inline void
203__rte_ring_dequeue_elems_64(void *obj_table, const void *ring_table,
204 uint32_t size, uint32_t idx, uint32_t n)
205{
206 unsigned int i;
207 unaligned_uint64_t *obj = (unaligned_uint64_t *)obj_table;
208 const uint64_t *ring = (const uint64_t *)ring_table;
209
210 if (likely(idx + n <= size)) {
211 for (i = 0; i < (n & ~0x3); i += 4, idx += 4) {
212 obj[i] = ring[idx];
213 obj[i + 1] = ring[idx + 1];
214 obj[i + 2] = ring[idx + 2];
215 obj[i + 3] = ring[idx + 3];
216 }
217 switch (n & 0x3) {
218 case 3:
219 obj[i++] = ring[idx++]; /* fallthrough */
220 case 2:
221 obj[i++] = ring[idx++]; /* fallthrough */
222 case 1:
223 obj[i++] = ring[idx++]; /* fallthrough */
224 }
225 } else {
226 for (i = 0; idx < size; i++, idx++)
227 obj[i] = ring[idx];
228 /* Start at the beginning */
229 for (idx = 0; i < n; i++, idx++)
230 obj[i] = ring[idx];
231 }
232}
233
234static __rte_always_inline void
235__rte_ring_dequeue_elems_128(void *obj_table, const void *ring_table,
236 uint32_t size, uint32_t idx, uint32_t n)
237{
238 unsigned int i;
239 rte_int128_t *obj = (rte_int128_t *)obj_table;
240 const rte_int128_t *ring = (const rte_int128_t *)ring_table;
241
242 if (likely(idx + n <= size)) {
243 for (i = 0; i < (n & ~0x1); i += 2, idx += 2)
244 memcpy((obj + i), (const void *)(ring + idx), 32);
245 switch (n & 0x1) {
246 case 1:
247 memcpy((obj + i), (const void *)(ring + idx), 16);
248 }
249 } else {
250 for (i = 0; idx < size; i++, idx++)
251 memcpy((obj + i), (const void *)(ring + idx), 16);
252 /* Start at the beginning */
253 for (idx = 0; i < n; i++, idx++)
254 memcpy((obj + i), (const void *)(ring + idx), 16);
255 }
256}
257
258/* the actual dequeue of elements from the ring.
259 * Placed here since identical code needed in both
260 * single and multi producer enqueue functions.
261 */
262static __rte_always_inline void
263__rte_ring_do_dequeue_elems(void *obj_table, const void *ring_table,
264 uint32_t size, uint32_t idx, uint32_t esize, uint32_t num)
265{
266 /* 8B and 16B copies implemented individually to retain
267 * the current performance.
268 */
269 if (esize == 8)
270 __rte_ring_dequeue_elems_64(obj_table, ring_table, size,
271 idx, num);
272 else if (esize == 16)
273 __rte_ring_dequeue_elems_128(obj_table, ring_table, size,
274 idx, num);
275 else {
276 uint32_t scale, nr_idx, nr_num, nr_size;
277
278 /* Normalize to uint32_t */
279 scale = esize / sizeof(uint32_t);
280 nr_num = num * scale;
281 nr_idx = idx * scale;
282 nr_size = size * scale;
283 __rte_ring_dequeue_elems_32(obj_table, ring_table, nr_size,
284 nr_idx, nr_num);
285 }
286}
287
288static __rte_always_inline void
289__rte_ring_dequeue_elems(struct rte_ring *r, uint32_t cons_head,
290 void *obj_table, uint32_t esize, uint32_t num)
291{
292 __rte_ring_do_dequeue_elems(obj_table, &r[1], r->size,
293 cons_head & r->mask, esize, num);
294}
295
296static __rte_always_inline void
297__rte_ring_update_tail(struct rte_ring_headtail *ht, uint32_t old_val,
298 uint32_t new_val, uint32_t single)
299{
300 /*
301 * If there are other enqueues/dequeues in progress that preceded us,
302 * we need to wait for them to complete
303 */
304 if (!single)
305 rte_wait_until_equal_32((uint32_t *)(uintptr_t)&ht->tail, old_val,
306 rte_memory_order_relaxed);
307
308 /*
309 * R0: Establishes a synchronizing edge with load-acquire of tail at A1.
310 * Ensures that memory effects by this thread on ring elements array
311 * is observed by a different thread of the other type.
312 */
313 rte_atomic_store_explicit(&ht->tail, new_val, rte_memory_order_release);
314}
315
316/*
317 * The function __rte_ring_headtail_move_head_mt,st has two versions
318 * based on what is most efficient on a given architecture.
319 *
320 * The C11 is preferred but on x86 GCC has 10% performance drop.
321 */
322#ifdef RTE_USE_C11_MEM_MODEL
323#include "rte_ring_c11_pvt.h"
324#else
325#include "rte_ring_gcc_pvt.h"
326#endif
327
351static __rte_always_inline unsigned int
352__rte_ring_move_prod_head(struct rte_ring *r, unsigned int is_sp,
353 unsigned int n, enum rte_ring_queue_behavior behavior,
354 uint32_t *old_head, uint32_t *new_head,
355 uint32_t *free_entries)
356{
357 if (is_sp)
358 return __rte_ring_headtail_move_head_st(&r->prod, &r->cons, r->capacity,
359 n, behavior, old_head, new_head, free_entries);
360 else
361 return __rte_ring_headtail_move_head_mt(&r->prod, &r->cons, r->capacity,
362 n, behavior, old_head, new_head, free_entries);
363}
364
388static __rte_always_inline unsigned int
389__rte_ring_move_cons_head(struct rte_ring *r, unsigned int is_sc,
390 unsigned int n, enum rte_ring_queue_behavior behavior,
391 uint32_t *old_head, uint32_t *new_head,
392 uint32_t *entries)
393{
394 if (is_sc)
395 return __rte_ring_headtail_move_head_st(&r->cons, &r->prod, 0,
396 n, behavior, old_head, new_head, entries);
397 else
398 return __rte_ring_headtail_move_head_mt(&r->cons, &r->prod, 0,
399 n, behavior, old_head, new_head, entries);
400}
401
426static __rte_always_inline unsigned int
427__rte_ring_do_enqueue_elem(struct rte_ring *r, const void *obj_table,
428 unsigned int esize, unsigned int n,
429 enum rte_ring_queue_behavior behavior, unsigned int is_sp,
430 unsigned int *free_space)
431{
432 uint32_t prod_head, prod_next;
433 uint32_t free_entries;
434
435 n = __rte_ring_move_prod_head(r, is_sp, n, behavior,
436 &prod_head, &prod_next, &free_entries);
437 if (n == 0)
438 goto end;
439
440 __rte_ring_enqueue_elems(r, prod_head, obj_table, esize, n);
441
442 __rte_ring_update_tail(&r->prod, prod_head, prod_next, is_sp);
443end:
444 if (free_space != NULL)
445 *free_space = free_entries - n;
446 return n;
447}
448
473static __rte_always_inline unsigned int
474__rte_ring_do_dequeue_elem(struct rte_ring *r, void *obj_table,
475 unsigned int esize, unsigned int n,
476 enum rte_ring_queue_behavior behavior, unsigned int is_sc,
477 unsigned int *available)
478{
479 uint32_t cons_head, cons_next;
480 uint32_t entries;
481
482 n = __rte_ring_move_cons_head(r, (int)is_sc, n, behavior,
483 &cons_head, &cons_next, &entries);
484 if (n == 0)
485 goto end;
486
487 __rte_ring_dequeue_elems(r, cons_head, obj_table, esize, n);
488
489 __rte_ring_update_tail(&r->cons, cons_head, cons_next, is_sc);
490
491end:
492 if (available != NULL)
493 *available = entries - n;
494 return n;
495}
496
497#endif /* _RTE_RING_ELEM_PVT_H_ */
#define likely(x)
#define __rte_always_inline
Definition: rte_common.h:534
static __rte_always_inline void rte_wait_until_equal_32(volatile uint32_t *addr, uint32_t expected, rte_memory_order memorder)
Definition: rte_pause.h:95
rte_ring_queue_behavior
Definition: rte_ring_core.h:40
uint32_t capacity
uint32_t size
uint32_t mask