blob: 41cd752914a463bdadc19c160409af461da66c52 [file] [log] [blame]
Dave Barach68b0fb02017-02-28 15:15:56 -05001/*
Florin Corasc5df8c72019-04-08 07:42:30 -07002 * Copyright (c) 2016-2019 Cisco and/or its affiliates.
Sirshak Das28aa5392019-02-05 01:33:33 -06003 * Copyright (c) 2019 Arm Limited
4 * Copyright (c) 2010-2017 Intel Corporation and/or its affiliates.
5 * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
6 * Inspired from DPDK rte_ring.h (SPSC only) (derived from freebsd bufring.h).
Dave Barach68b0fb02017-02-28 15:15:56 -05007 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at:
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
Florin Coras6792ec02017-03-13 03:49:51 -070020#include <svm/svm_fifo.h>
Florin Corasf6359c82017-06-19 12:26:09 -040021#include <vppinfra/cpu.h>
Dave Barach68b0fb02017-02-28 15:15:56 -050022
Florin Corasf03a59a2017-06-09 21:07:32 -070023static inline u8
Sirshak Das28aa5392019-02-05 01:33:33 -060024position_lt (svm_fifo_t * f, u32 a, u32 b, u32 tail)
Florin Corasf03a59a2017-06-09 21:07:32 -070025{
Sirshak Das28aa5392019-02-05 01:33:33 -060026 return (ooo_segment_distance_from_tail (f, a, tail)
27 < ooo_segment_distance_from_tail (f, b, tail));
Florin Corasf03a59a2017-06-09 21:07:32 -070028}
29
30static inline u8
Sirshak Das28aa5392019-02-05 01:33:33 -060031position_leq (svm_fifo_t * f, u32 a, u32 b, u32 tail)
Florin Corasf03a59a2017-06-09 21:07:32 -070032{
Sirshak Das28aa5392019-02-05 01:33:33 -060033 return (ooo_segment_distance_from_tail (f, a, tail)
34 <= ooo_segment_distance_from_tail (f, b, tail));
Florin Corasf03a59a2017-06-09 21:07:32 -070035}
36
37static inline u8
Sirshak Das28aa5392019-02-05 01:33:33 -060038position_gt (svm_fifo_t * f, u32 a, u32 b, u32 tail)
Florin Corasf03a59a2017-06-09 21:07:32 -070039{
Sirshak Das28aa5392019-02-05 01:33:33 -060040 return (ooo_segment_distance_from_tail (f, a, tail)
41 > ooo_segment_distance_from_tail (f, b, tail));
Florin Corasf03a59a2017-06-09 21:07:32 -070042}
43
44static inline u32
Sirshak Das28aa5392019-02-05 01:33:33 -060045position_diff (svm_fifo_t * f, u32 posa, u32 posb, u32 tail)
Florin Corasf03a59a2017-06-09 21:07:32 -070046{
Sirshak Das28aa5392019-02-05 01:33:33 -060047 return ooo_segment_distance_from_tail (f, posa, tail)
48 - ooo_segment_distance_from_tail (f, posb, tail);
Florin Corasf03a59a2017-06-09 21:07:32 -070049}
50
51static inline u32
52ooo_segment_end_pos (svm_fifo_t * f, ooo_segment_t * s)
53{
Sirshak Das28aa5392019-02-05 01:33:33 -060054 return s->start + s->length;
Florin Corasf03a59a2017-06-09 21:07:32 -070055}
Dave Barach1f75cfd2017-04-14 16:46:44 -040056
Florin Coras3aa7af32018-06-29 08:44:31 -070057#ifndef CLIB_MARCH_VARIANT
58
Dave Barach1f75cfd2017-04-14 16:46:44 -040059u8 *
60format_ooo_segment (u8 * s, va_list * args)
61{
Florin Coras1f152cd2017-08-18 19:28:03 -070062 svm_fifo_t *f = va_arg (*args, svm_fifo_t *);
Dave Barach1f75cfd2017-04-14 16:46:44 -040063 ooo_segment_t *seg = va_arg (*args, ooo_segment_t *);
Sirshak Das28aa5392019-02-05 01:33:33 -060064 u32 normalized_start = (seg->start + f->nitems - f->tail) % f->size;
Florin Coras1f152cd2017-08-18 19:28:03 -070065 s = format (s, "[%u, %u], len %u, next %d, prev %d", normalized_start,
Sirshak Das28aa5392019-02-05 01:33:33 -060066 (normalized_start + seg->length) % f->size, seg->length,
Florin Coras1f152cd2017-08-18 19:28:03 -070067 seg->next, seg->prev);
Dave Barach1f75cfd2017-04-14 16:46:44 -040068 return s;
69}
70
71u8 *
Florin Coras3eb50622017-07-13 01:24:57 -040072svm_fifo_dump_trace (u8 * s, svm_fifo_t * f)
73{
74#if SVM_FIFO_TRACE
75 svm_fifo_trace_elem_t *seg = 0;
76 int i = 0;
77
78 if (f->trace)
79 {
80 vec_foreach (seg, f->trace)
81 {
82 s = format (s, "{%u, %u, %u}, ", seg->offset, seg->len, seg->action);
83 i++;
84 if (i % 5 == 0)
85 s = format (s, "\n");
86 }
87 s = format (s, "\n");
88 }
89 return s;
90#else
91 return 0;
92#endif
93}
94
95u8 *
96svm_fifo_replay (u8 * s, svm_fifo_t * f, u8 no_read, u8 verbose)
97{
98 int i, trace_len;
99 u8 *data = 0;
100 svm_fifo_trace_elem_t *trace;
101 u32 offset;
102 svm_fifo_t *dummy_fifo;
103
104 if (!f)
105 return s;
106
107#if SVM_FIFO_TRACE
108 trace = f->trace;
109 trace_len = vec_len (trace);
110#else
111 trace = 0;
112 trace_len = 0;
113#endif
114
Sirshak Das28aa5392019-02-05 01:33:33 -0600115 dummy_fifo = svm_fifo_create (f->size);
Florin Coras0a846802019-04-09 18:29:14 -0700116 clib_memset (f->head_chunk->data, 0xFF, f->nitems);
Florin Coras3eb50622017-07-13 01:24:57 -0400117 vec_validate (data, f->nitems);
118 for (i = 0; i < vec_len (data); i++)
119 data[i] = i;
120
121 for (i = 0; i < trace_len; i++)
122 {
123 offset = trace[i].offset;
124 if (trace[i].action == 1)
125 {
126 if (verbose)
127 s = format (s, "adding [%u, %u]:", trace[i].offset,
Sirshak Das28aa5392019-02-05 01:33:33 -0600128 (trace[i].offset + trace[i].len) % dummy_fifo->size);
Florin Coras3eb50622017-07-13 01:24:57 -0400129 svm_fifo_enqueue_with_offset (dummy_fifo, trace[i].offset,
130 trace[i].len, &data[offset]);
131 }
132 else if (trace[i].action == 2)
133 {
134 if (verbose)
135 s = format (s, "adding [%u, %u]:", 0, trace[i].len);
136 svm_fifo_enqueue_nowait (dummy_fifo, trace[i].len, &data[offset]);
137 }
138 else if (!no_read)
139 {
140 if (verbose)
141 s = format (s, "read: %u", trace[i].len);
142 svm_fifo_dequeue_drop (dummy_fifo, trace[i].len);
143 }
144 if (verbose)
145 s = format (s, "%U", format_svm_fifo, dummy_fifo, 1);
146 }
147
148 s = format (s, "result: %U", format_svm_fifo, dummy_fifo, 1);
149
150 return s;
151}
152
153u8 *
Dave Barach1f75cfd2017-04-14 16:46:44 -0400154format_ooo_list (u8 * s, va_list * args)
155{
156 svm_fifo_t *f = va_arg (*args, svm_fifo_t *);
Florin Corasde9a8492018-10-24 22:18:58 -0700157 u32 indent = va_arg (*args, u32);
Dave Barach1f75cfd2017-04-14 16:46:44 -0400158 u32 ooo_segment_index = f->ooos_list_head;
159 ooo_segment_t *seg;
160
161 while (ooo_segment_index != OOO_SEGMENT_INVALID_INDEX)
162 {
163 seg = pool_elt_at_index (f->ooo_segments, ooo_segment_index);
Florin Corasde9a8492018-10-24 22:18:58 -0700164 s = format (s, "%U%U\n", format_white_space, indent, format_ooo_segment,
165 f, seg);
Dave Barach1f75cfd2017-04-14 16:46:44 -0400166 ooo_segment_index = seg->next;
167 }
Florin Coras3eb50622017-07-13 01:24:57 -0400168
Dave Barach1f75cfd2017-04-14 16:46:44 -0400169 return s;
170}
171
Florin Corasb59a7052017-04-18 22:07:29 -0700172u8 *
173format_svm_fifo (u8 * s, va_list * args)
174{
175 svm_fifo_t *f = va_arg (*args, svm_fifo_t *);
176 int verbose = va_arg (*args, int);
Florin Corasde9a8492018-10-24 22:18:58 -0700177 u32 indent;
Florin Corasb59a7052017-04-18 22:07:29 -0700178
Florin Coras7fb0fe12018-04-09 09:24:52 -0700179 if (!s)
180 return s;
181
Florin Corasde9a8492018-10-24 22:18:58 -0700182 indent = format_get_indent (s);
Florin Corasb59a7052017-04-18 22:07:29 -0700183 s = format (s, "cursize %u nitems %u has_event %d\n",
Sirshak Das28aa5392019-02-05 01:33:33 -0600184 svm_fifo_max_dequeue (f), f->nitems, f->has_event);
185 s = format (s, "%Uhead %u tail %u segment manager %u\n", format_white_space,
186 indent, (f->head % f->size), (f->tail % f->size),
187 f->segment_manager);
Florin Corasb59a7052017-04-18 22:07:29 -0700188
189 if (verbose > 1)
Florin Corasde9a8492018-10-24 22:18:58 -0700190 s = format (s, "%Uvpp session %d thread %d app session %d thread %d\n",
191 format_white_space, indent, f->master_session_index,
192 f->master_thread_index, f->client_session_index,
193 f->client_thread_index);
Florin Corasb59a7052017-04-18 22:07:29 -0700194
195 if (verbose)
196 {
Florin Corasde9a8492018-10-24 22:18:58 -0700197 s = format (s, "%Uooo pool %d active elts newest %u\n",
198 format_white_space, indent, pool_elts (f->ooo_segments),
199 f->ooos_newest);
Florin Corasbb292f42017-05-19 09:49:19 -0700200 if (svm_fifo_has_ooo_data (f))
Florin Corasde9a8492018-10-24 22:18:58 -0700201 s = format (s, " %U", format_ooo_list, f, indent, verbose);
Florin Corasb59a7052017-04-18 22:07:29 -0700202 }
203 return s;
204}
205
Florin Coras0a846802019-04-09 18:29:14 -0700206void
207svm_fifo_init (svm_fifo_t * f, u32 size)
208{
209 f->size = size;
210 /*
211 * usable size of the fifo set to rounded_data_size - 1
212 * to differentiate between free fifo and empty fifo.
213 */
214 f->nitems = f->size - 1;
215 f->ooos_list_head = OOO_SEGMENT_INVALID_INDEX;
216 f->ct_session_index = SVM_FIFO_INVALID_SESSION_INDEX;
217 f->segment_index = SVM_FIFO_INVALID_INDEX;
218 f->refcnt = 1;
Florin Coras0a846802019-04-09 18:29:14 -0700219 f->default_chunk.start_byte = 0;
220 f->default_chunk.length = f->size;
Florin Coras2309e7a2019-04-18 18:58:10 -0700221 f->default_chunk.next = f->start_chunk = &f->default_chunk;
222 f->end_chunk = f->head_chunk = f->tail_chunk = f->start_chunk;
Florin Coras0a846802019-04-09 18:29:14 -0700223}
224
Dave Barach68b0fb02017-02-28 15:15:56 -0500225/** create an svm fifo, in the current heap. Fails vs blow up the process */
226svm_fifo_t *
227svm_fifo_create (u32 data_size_in_bytes)
228{
229 svm_fifo_t *f;
Dave Barach818eb542017-08-02 13:56:13 -0400230 u32 rounded_data_size;
Dave Barach68b0fb02017-02-28 15:15:56 -0500231
Dave Barach818eb542017-08-02 13:56:13 -0400232 /* always round fifo data size to the next highest power-of-two */
233 rounded_data_size = (1 << (max_log2 (data_size_in_bytes)));
234 f = clib_mem_alloc_aligned_or_null (sizeof (*f) + rounded_data_size,
Dave Barach68b0fb02017-02-28 15:15:56 -0500235 CLIB_CACHE_LINE_BYTES);
236 if (f == 0)
237 return 0;
238
Dave Barachb7b92992018-10-17 10:38:51 -0400239 clib_memset (f, 0, sizeof (*f));
Florin Coras0a846802019-04-09 18:29:14 -0700240 svm_fifo_init (f, data_size_in_bytes);
241 return f;
Dave Barach68b0fb02017-02-28 15:15:56 -0500242}
243
Florin Coras6cf30ad2017-04-04 23:08:23 -0700244void
245svm_fifo_free (svm_fifo_t * f)
246{
Dave Barach52851e62017-08-07 09:35:25 -0400247 ASSERT (f->refcnt > 0);
248
249 if (--f->refcnt == 0)
250 {
251 pool_free (f->ooo_segments);
252 clib_mem_free (f);
253 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700254}
Florin Coras3aa7af32018-06-29 08:44:31 -0700255#endif
Florin Coras6cf30ad2017-04-04 23:08:23 -0700256
Dave Barach68b0fb02017-02-28 15:15:56 -0500257always_inline ooo_segment_t *
258ooo_segment_new (svm_fifo_t * f, u32 start, u32 length)
259{
260 ooo_segment_t *s;
261
262 pool_get (f->ooo_segments, s);
263
Dave Barach1f75cfd2017-04-14 16:46:44 -0400264 s->start = start;
Dave Barach68b0fb02017-02-28 15:15:56 -0500265 s->length = length;
266
267 s->prev = s->next = OOO_SEGMENT_INVALID_INDEX;
268
269 return s;
270}
271
272always_inline void
273ooo_segment_del (svm_fifo_t * f, u32 index)
274{
275 ooo_segment_t *cur, *prev = 0, *next = 0;
276 cur = pool_elt_at_index (f->ooo_segments, index);
277
278 if (cur->next != OOO_SEGMENT_INVALID_INDEX)
279 {
280 next = pool_elt_at_index (f->ooo_segments, cur->next);
281 next->prev = cur->prev;
282 }
283
284 if (cur->prev != OOO_SEGMENT_INVALID_INDEX)
285 {
286 prev = pool_elt_at_index (f->ooo_segments, cur->prev);
287 prev->next = cur->next;
288 }
289 else
290 {
291 f->ooos_list_head = cur->next;
292 }
293
294 pool_put (f->ooo_segments, cur);
295}
296
297/**
298 * Add segment to fifo's out-of-order segment list. Takes care of merging
299 * adjacent segments and removing overlapping ones.
300 */
301static void
Sirshak Das28aa5392019-02-05 01:33:33 -0600302ooo_segment_add (svm_fifo_t * f, u32 offset, u32 head, u32 tail, u32 length)
Dave Barach68b0fb02017-02-28 15:15:56 -0500303{
304 ooo_segment_t *s, *new_s, *prev, *next, *it;
Florin Corasf03a59a2017-06-09 21:07:32 -0700305 u32 new_index, s_end_pos, s_index;
Sirshak Das28aa5392019-02-05 01:33:33 -0600306 u32 offset_pos, offset_end_pos;
Dave Barach68b0fb02017-02-28 15:15:56 -0500307
Florin Coras0a846802019-04-09 18:29:14 -0700308 ASSERT (offset + length <= ooo_segment_distance_from_tail (f, head, tail)
309 || head == tail);
310
Sirshak Das28aa5392019-02-05 01:33:33 -0600311 offset_pos = tail + offset;
312 offset_end_pos = tail + offset + length;
Florin Corasf03a59a2017-06-09 21:07:32 -0700313
314 f->ooos_newest = OOO_SEGMENT_INVALID_INDEX;
Dave Barach68b0fb02017-02-28 15:15:56 -0500315
316 if (f->ooos_list_head == OOO_SEGMENT_INVALID_INDEX)
317 {
Sirshak Das28aa5392019-02-05 01:33:33 -0600318 s = ooo_segment_new (f, offset_pos, length);
Dave Barach68b0fb02017-02-28 15:15:56 -0500319 f->ooos_list_head = s - f->ooo_segments;
320 f->ooos_newest = f->ooos_list_head;
321 return;
322 }
323
324 /* Find first segment that starts after new segment */
325 s = pool_elt_at_index (f->ooo_segments, f->ooos_list_head);
326 while (s->next != OOO_SEGMENT_INVALID_INDEX
Sirshak Das28aa5392019-02-05 01:33:33 -0600327 && position_lt (f, s->start, offset_pos, tail))
Dave Barach68b0fb02017-02-28 15:15:56 -0500328 s = pool_elt_at_index (f->ooo_segments, s->next);
329
Florin Corasc28764f2017-04-26 00:08:42 -0700330 /* If we have a previous and we overlap it, use it as starting point */
331 prev = ooo_segment_get_prev (f, s);
Florin Corasf03a59a2017-06-09 21:07:32 -0700332 if (prev
Sirshak Das28aa5392019-02-05 01:33:33 -0600333 && position_leq (f, offset_pos, ooo_segment_end_pos (f, prev), tail))
Florin Corasc28764f2017-04-26 00:08:42 -0700334 {
335 s = prev;
Florin Corasf03a59a2017-06-09 21:07:32 -0700336 s_end_pos = ooo_segment_end_pos (f, s);
Dave Barach2c25a622017-06-26 11:35:07 -0400337
Sirshak Das28aa5392019-02-05 01:33:33 -0600338 /* Since we have previous, offset start position cannot be smaller
Florin Coras3eb50622017-07-13 01:24:57 -0400339 * than prev->start. Check tail */
Sirshak Das28aa5392019-02-05 01:33:33 -0600340 ASSERT (position_lt (f, s->start, offset_pos, tail));
Dave Barach2c25a622017-06-26 11:35:07 -0400341 goto check_tail;
Florin Corasc28764f2017-04-26 00:08:42 -0700342 }
343
Dave Barach68b0fb02017-02-28 15:15:56 -0500344 s_index = s - f->ooo_segments;
Florin Corasf03a59a2017-06-09 21:07:32 -0700345 s_end_pos = ooo_segment_end_pos (f, s);
Dave Barach68b0fb02017-02-28 15:15:56 -0500346
347 /* No overlap, add before current segment */
Sirshak Das28aa5392019-02-05 01:33:33 -0600348 if (position_lt (f, offset_end_pos, s->start, tail))
Dave Barach68b0fb02017-02-28 15:15:56 -0500349 {
Sirshak Das28aa5392019-02-05 01:33:33 -0600350 new_s = ooo_segment_new (f, offset_pos, length);
Dave Barach68b0fb02017-02-28 15:15:56 -0500351 new_index = new_s - f->ooo_segments;
352
353 /* Pool might've moved, get segment again */
354 s = pool_elt_at_index (f->ooo_segments, s_index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500355 if (s->prev != OOO_SEGMENT_INVALID_INDEX)
356 {
357 new_s->prev = s->prev;
Dave Barach68b0fb02017-02-28 15:15:56 -0500358 prev = pool_elt_at_index (f->ooo_segments, new_s->prev);
359 prev->next = new_index;
360 }
361 else
362 {
363 /* New head */
364 f->ooos_list_head = new_index;
365 }
366
Florin Corasf03a59a2017-06-09 21:07:32 -0700367 new_s->next = s_index;
Dave Barach68b0fb02017-02-28 15:15:56 -0500368 s->prev = new_index;
369 f->ooos_newest = new_index;
370 return;
371 }
372 /* No overlap, add after current segment */
Sirshak Das28aa5392019-02-05 01:33:33 -0600373 else if (position_gt (f, offset_pos, s_end_pos, tail))
Dave Barach68b0fb02017-02-28 15:15:56 -0500374 {
Sirshak Das28aa5392019-02-05 01:33:33 -0600375 new_s = ooo_segment_new (f, offset_pos, length);
Dave Barach68b0fb02017-02-28 15:15:56 -0500376 new_index = new_s - f->ooo_segments;
377
378 /* Pool might've moved, get segment again */
379 s = pool_elt_at_index (f->ooo_segments, s_index);
380
Florin Coras3eb50622017-07-13 01:24:57 -0400381 /* Needs to be last */
Florin Corasf03a59a2017-06-09 21:07:32 -0700382 ASSERT (s->next == OOO_SEGMENT_INVALID_INDEX);
Dave Barach68b0fb02017-02-28 15:15:56 -0500383
Florin Corasf03a59a2017-06-09 21:07:32 -0700384 new_s->prev = s_index;
Dave Barach68b0fb02017-02-28 15:15:56 -0500385 s->next = new_index;
386 f->ooos_newest = new_index;
387
388 return;
389 }
390
391 /*
392 * Merge needed
393 */
394
395 /* Merge at head */
Sirshak Das28aa5392019-02-05 01:33:33 -0600396 if (position_lt (f, offset_pos, s->start, tail))
Dave Barach68b0fb02017-02-28 15:15:56 -0500397 {
Sirshak Das28aa5392019-02-05 01:33:33 -0600398 s->start = offset_pos;
399 s->length = position_diff (f, s_end_pos, s->start, tail);
Florin Coras3eb50622017-07-13 01:24:57 -0400400 f->ooos_newest = s - f->ooo_segments;
Dave Barach68b0fb02017-02-28 15:15:56 -0500401 }
402
Dave Barach2c25a622017-06-26 11:35:07 -0400403check_tail:
Florin Coras3eb50622017-07-13 01:24:57 -0400404
405 /* Overlapping tail */
Sirshak Das28aa5392019-02-05 01:33:33 -0600406 if (position_gt (f, offset_end_pos, s_end_pos, tail))
Florin Corasc28764f2017-04-26 00:08:42 -0700407 {
Sirshak Das28aa5392019-02-05 01:33:33 -0600408 s->length = position_diff (f, offset_end_pos, s->start, tail);
Florin Coras3eb50622017-07-13 01:24:57 -0400409
410 /* Remove the completely overlapped segments in the tail */
411 it = ooo_segment_next (f, s);
Florin Corasf03a59a2017-06-09 21:07:32 -0700412 while (it && position_leq (f, ooo_segment_end_pos (f, it),
Sirshak Das28aa5392019-02-05 01:33:33 -0600413 offset_end_pos, tail))
Florin Corasc28764f2017-04-26 00:08:42 -0700414 {
Florin Coras3eb50622017-07-13 01:24:57 -0400415 next = ooo_segment_next (f, it);
Florin Corasc28764f2017-04-26 00:08:42 -0700416 ooo_segment_del (f, it - f->ooo_segments);
417 it = next;
418 }
419
420 /* If partial overlap with last, merge */
Sirshak Das28aa5392019-02-05 01:33:33 -0600421 if (it && position_leq (f, it->start, offset_end_pos, tail))
Florin Corasc28764f2017-04-26 00:08:42 -0700422 {
Florin Coras3eb50622017-07-13 01:24:57 -0400423 s->length = position_diff (f, ooo_segment_end_pos (f, it),
Sirshak Das28aa5392019-02-05 01:33:33 -0600424 s->start, tail);
Florin Corasc28764f2017-04-26 00:08:42 -0700425 ooo_segment_del (f, it - f->ooo_segments);
426 }
Florin Coras3eb50622017-07-13 01:24:57 -0400427 f->ooos_newest = s - f->ooo_segments;
Florin Corasc28764f2017-04-26 00:08:42 -0700428 }
Dave Barach68b0fb02017-02-28 15:15:56 -0500429}
430
431/**
432 * Removes segments that can now be enqueued because the fifo's tail has
433 * advanced. Returns the number of bytes added to tail.
434 */
435static int
Sirshak Das28aa5392019-02-05 01:33:33 -0600436ooo_segment_try_collect (svm_fifo_t * f, u32 n_bytes_enqueued, u32 * tail)
Dave Barach68b0fb02017-02-28 15:15:56 -0500437{
438 ooo_segment_t *s;
Florin Corasf03a59a2017-06-09 21:07:32 -0700439 u32 index, bytes = 0;
440 i32 diff;
Dave Barach68b0fb02017-02-28 15:15:56 -0500441
442 s = pool_elt_at_index (f->ooo_segments, f->ooos_list_head);
Sirshak Das28aa5392019-02-05 01:33:33 -0600443 diff = ooo_segment_distance_to_tail (f, s->start, *tail);
Dave Barach68b0fb02017-02-28 15:15:56 -0500444
Dave Barach2c25a622017-06-26 11:35:07 -0400445 ASSERT (diff != n_bytes_enqueued);
Florin Corasc28764f2017-04-26 00:08:42 -0700446
Florin Corasf03a59a2017-06-09 21:07:32 -0700447 if (diff > n_bytes_enqueued)
Florin Corasb59a7052017-04-18 22:07:29 -0700448 return 0;
449
Dave Barach68b0fb02017-02-28 15:15:56 -0500450 /* If last tail update overlaps one/multiple ooo segments, remove them */
Florin Corasf03a59a2017-06-09 21:07:32 -0700451 while (0 <= diff && diff < n_bytes_enqueued)
Dave Barach68b0fb02017-02-28 15:15:56 -0500452 {
Florin Corasb59a7052017-04-18 22:07:29 -0700453 index = s - f->ooo_segments;
454
455 /* Segment end is beyond the tail. Advance tail and remove segment */
Florin Corasf03a59a2017-06-09 21:07:32 -0700456 if (s->length > diff)
Dave Barach68b0fb02017-02-28 15:15:56 -0500457 {
Florin Corasb59a7052017-04-18 22:07:29 -0700458 bytes = s->length - diff;
Sirshak Das28aa5392019-02-05 01:33:33 -0600459 *tail = *tail + bytes;
Florin Corasb59a7052017-04-18 22:07:29 -0700460 ooo_segment_del (f, index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500461 break;
462 }
Florin Corasb59a7052017-04-18 22:07:29 -0700463
Dave Barach68b0fb02017-02-28 15:15:56 -0500464 /* If we have next go on */
Florin Corasb59a7052017-04-18 22:07:29 -0700465 if (s->next != OOO_SEGMENT_INVALID_INDEX)
Dave Barach68b0fb02017-02-28 15:15:56 -0500466 {
Dave Barach68b0fb02017-02-28 15:15:56 -0500467 s = pool_elt_at_index (f->ooo_segments, s->next);
Sirshak Das28aa5392019-02-05 01:33:33 -0600468 diff = ooo_segment_distance_to_tail (f, s->start, *tail);
Dave Barach68b0fb02017-02-28 15:15:56 -0500469 ooo_segment_del (f, index);
470 }
471 /* End of search */
472 else
473 {
Florin Corasb59a7052017-04-18 22:07:29 -0700474 ooo_segment_del (f, index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500475 break;
476 }
477 }
478
Chris Lukeab7b8d92017-09-07 07:40:13 -0400479 ASSERT (bytes <= f->nitems);
Dave Barach68b0fb02017-02-28 15:15:56 -0500480 return bytes;
481}
482
Florin Coras0a846802019-04-09 18:29:14 -0700483CLIB_MARCH_FN (svm_fifo_enqueue_nowait, int, svm_fifo_t * f, u32 len,
484 const u8 * src)
Dave Barach68b0fb02017-02-28 15:15:56 -0500485{
Florin Coras0a846802019-04-09 18:29:14 -0700486 u32 n_chunk, to_copy, tail, head, free_count, tail_idx;
487 svm_fifo_chunk_t *c;
Dave Barach68b0fb02017-02-28 15:15:56 -0500488
Sirshak Das28aa5392019-02-05 01:33:33 -0600489 f_load_head_tail_prod (f, &head, &tail);
490
491 /* free space in fifo can only increase during enqueue: SPSC */
492 free_count = f_free_count (f, head, tail);
493
Florin Corasf03a59a2017-06-09 21:07:32 -0700494 f->ooos_newest = OOO_SEGMENT_INVALID_INDEX;
Florin Coras3e350af2017-03-30 02:54:28 -0700495
Sirshak Das28aa5392019-02-05 01:33:33 -0600496 if (PREDICT_FALSE (free_count == 0))
Florin Coras7fb0fe12018-04-09 09:24:52 -0700497 return SVM_FIFO_FULL;
Dave Barach68b0fb02017-02-28 15:15:56 -0500498
Sirshak Das28aa5392019-02-05 01:33:33 -0600499 /* number of bytes we're going to copy */
Florin Coras0a846802019-04-09 18:29:14 -0700500 to_copy = len = clib_min (free_count, len);
Dave Barach68b0fb02017-02-28 15:15:56 -0500501
Florin Coras0a846802019-04-09 18:29:14 -0700502 c = f->tail_chunk;
Sirshak Das28aa5392019-02-05 01:33:33 -0600503 tail_idx = tail % f->size;
Florin Coras0a846802019-04-09 18:29:14 -0700504 ASSERT (tail_idx >= c->start_byte);
505 tail_idx -= c->start_byte;
506 n_chunk = c->length - tail_idx;
Dave Barach68b0fb02017-02-28 15:15:56 -0500507
Florin Coras0a846802019-04-09 18:29:14 -0700508 if (n_chunk < to_copy)
Dave Barach68b0fb02017-02-28 15:15:56 -0500509 {
Florin Coras0a846802019-04-09 18:29:14 -0700510 clib_memcpy_fast (&c->data[tail_idx], src, n_chunk);
511 while ((to_copy -= n_chunk))
Dave Barach68b0fb02017-02-28 15:15:56 -0500512 {
Florin Coras0a846802019-04-09 18:29:14 -0700513 c = c->next;
514 n_chunk = clib_min (c->length, to_copy);
515 clib_memcpy_fast (&c->data[0], src + (len - to_copy), n_chunk);
Dave Barach68b0fb02017-02-28 15:15:56 -0500516 }
Florin Coras0a846802019-04-09 18:29:14 -0700517 f->tail_chunk = c;
Dave Barach68b0fb02017-02-28 15:15:56 -0500518 }
519 else
520 {
Florin Coras0a846802019-04-09 18:29:14 -0700521 clib_memcpy_fast (&c->data[tail_idx], src, to_copy);
Dave Barach68b0fb02017-02-28 15:15:56 -0500522 }
Florin Coras0a846802019-04-09 18:29:14 -0700523 tail += len;
Dave Barach68b0fb02017-02-28 15:15:56 -0500524
Florin Coras0a846802019-04-09 18:29:14 -0700525 svm_fifo_trace_add (f, head, n_total, 2);
Florin Coras3eb50622017-07-13 01:24:57 -0400526
Sirshak Das28aa5392019-02-05 01:33:33 -0600527 /* collect out-of-order segments */
Dave Barach68b0fb02017-02-28 15:15:56 -0500528 if (PREDICT_FALSE (f->ooos_list_head != OOO_SEGMENT_INVALID_INDEX))
Florin Coras0a846802019-04-09 18:29:14 -0700529 len += ooo_segment_try_collect (f, len, &tail);
Dave Barach68b0fb02017-02-28 15:15:56 -0500530
Florin Coras0a846802019-04-09 18:29:14 -0700531 ASSERT (len <= free_count);
Dave Barach68b0fb02017-02-28 15:15:56 -0500532
Sirshak Das28aa5392019-02-05 01:33:33 -0600533 /* store-rel: producer owned index (paired with load-acq in consumer) */
534 clib_atomic_store_rel_n (&f->tail, tail);
535
Florin Coras0a846802019-04-09 18:29:14 -0700536 return len;
Dave Barach68b0fb02017-02-28 15:15:56 -0500537}
538
Florin Coras3aa7af32018-06-29 08:44:31 -0700539#ifndef CLIB_MARCH_VARIANT
Dave Barach68b0fb02017-02-28 15:15:56 -0500540int
Florin Coras371ca502018-02-21 12:07:41 -0800541svm_fifo_enqueue_nowait (svm_fifo_t * f, u32 max_bytes,
542 const u8 * copy_from_here)
Dave Barach68b0fb02017-02-28 15:15:56 -0500543{
Florin Coras983cc7d2018-09-18 23:11:55 -0700544 return CLIB_MARCH_FN_SELECT (svm_fifo_enqueue_nowait) (f, max_bytes,
545 copy_from_here);
Dave Barach68b0fb02017-02-28 15:15:56 -0500546}
Florin Coras3aa7af32018-06-29 08:44:31 -0700547#endif
Dave Barach68b0fb02017-02-28 15:15:56 -0500548
Florin Coras6792ec02017-03-13 03:49:51 -0700549/**
550 * Enqueue a future segment.
551 *
Dave Barach68b0fb02017-02-28 15:15:56 -0500552 * Two choices: either copies the entire segment, or copies nothing
553 * Returns 0 of the entire segment was copied
554 * Returns -1 if none of the segment was copied due to lack of space
555 */
Florin Coras983cc7d2018-09-18 23:11:55 -0700556CLIB_MARCH_FN (svm_fifo_enqueue_with_offset, int, svm_fifo_t * f,
Florin Coras0a846802019-04-09 18:29:14 -0700557 u32 offset, u32 len, u8 * src)
Dave Barach68b0fb02017-02-28 15:15:56 -0500558{
Florin Coras0a846802019-04-09 18:29:14 -0700559 u32 to_copy, n_chunk, tail, head, free_count, tail_offset_idx;
560 svm_fifo_chunk_t *c;
Sirshak Das28aa5392019-02-05 01:33:33 -0600561
562 f_load_head_tail_prod (f, &head, &tail);
563
564 /* free space in fifo can only increase during enqueue: SPSC */
565 free_count = f_free_count (f, head, tail);
566
567 /* will this request fit? */
Florin Coras0a846802019-04-09 18:29:14 -0700568 if ((len + offset) > free_count)
Sirshak Das28aa5392019-02-05 01:33:33 -0600569 return -1;
Florin Corasf03a59a2017-06-09 21:07:32 -0700570
571 f->ooos_newest = OOO_SEGMENT_INVALID_INDEX;
Dave Barach68b0fb02017-02-28 15:15:56 -0500572
Florin Coras0a846802019-04-09 18:29:14 -0700573 ASSERT (len < f->nitems);
574 svm_fifo_trace_add (f, offset, len, 1);
Florin Corasf03a59a2017-06-09 21:07:32 -0700575
Florin Coras0a846802019-04-09 18:29:14 -0700576 ooo_segment_add (f, offset, head, tail, len);
Dave Barach68b0fb02017-02-28 15:15:56 -0500577
Florin Coras0a846802019-04-09 18:29:14 -0700578 c = f->tail_chunk;
579 tail_offset_idx = (tail + offset) % f->size;
580 tail_offset_idx -= c->start_byte;
581 n_chunk = c->length - tail_offset_idx;
582 to_copy = len;
Florin Coras3eb50622017-07-13 01:24:57 -0400583
Florin Coras0a846802019-04-09 18:29:14 -0700584 if (n_chunk < to_copy)
Dave Barach68b0fb02017-02-28 15:15:56 -0500585 {
Florin Coras0a846802019-04-09 18:29:14 -0700586 clib_memcpy_fast (&c->data[tail_offset_idx], src, n_chunk);
587 while ((to_copy -= n_chunk))
588 {
589 c = c->next;
590 n_chunk = clib_min (c->length, to_copy);
591 clib_memcpy_fast (&c->data[0], src + (len - to_copy), n_chunk);
592 }
Dave Barach68b0fb02017-02-28 15:15:56 -0500593 }
Sirshak Das28aa5392019-02-05 01:33:33 -0600594 else
595 {
Florin Coras0a846802019-04-09 18:29:14 -0700596 clib_memcpy_fast (&c->data[tail_offset_idx], src, len);
Sirshak Das28aa5392019-02-05 01:33:33 -0600597 }
Dave Barach68b0fb02017-02-28 15:15:56 -0500598
Sirshak Das28aa5392019-02-05 01:33:33 -0600599 return 0;
Dave Barach68b0fb02017-02-28 15:15:56 -0500600}
601
Florin Coras3aa7af32018-06-29 08:44:31 -0700602#ifndef CLIB_MARCH_VARIANT
Dave Barach68b0fb02017-02-28 15:15:56 -0500603
604int
Florin Coras3aa7af32018-06-29 08:44:31 -0700605svm_fifo_enqueue_with_offset (svm_fifo_t * f, u32 offset, u32 required_bytes,
606 u8 * copy_from_here)
Dave Barach68b0fb02017-02-28 15:15:56 -0500607{
Florin Coras983cc7d2018-09-18 23:11:55 -0700608 return CLIB_MARCH_FN_SELECT (svm_fifo_enqueue_with_offset) (f, offset,
609 required_bytes,
610 copy_from_here);
Dave Barach68b0fb02017-02-28 15:15:56 -0500611}
612
Florin Coras7fb0fe12018-04-09 09:24:52 -0700613void
614svm_fifo_overwrite_head (svm_fifo_t * f, u8 * data, u32 len)
615{
Florin Coras0a846802019-04-09 18:29:14 -0700616 u32 n_chunk;
Sirshak Das28aa5392019-02-05 01:33:33 -0600617 u32 head, tail, head_idx;
Florin Coras0a846802019-04-09 18:29:14 -0700618 svm_fifo_chunk_t *c;
619
620 ASSERT (len <= f->nitems);
Sirshak Das28aa5392019-02-05 01:33:33 -0600621
622 f_load_head_tail_cons (f, &head, &tail);
Florin Coras0a846802019-04-09 18:29:14 -0700623 c = f->head_chunk;
Sirshak Das28aa5392019-02-05 01:33:33 -0600624 head_idx = head % f->size;
Florin Coras0a846802019-04-09 18:29:14 -0700625 head_idx -= c->start_byte;
626 n_chunk = c->length - head_idx;
627 if (len <= n_chunk)
628 clib_memcpy_fast (&c->data[head_idx], data, len);
Florin Coras7fb0fe12018-04-09 09:24:52 -0700629 else
630 {
Florin Coras0a846802019-04-09 18:29:14 -0700631 clib_memcpy_fast (&c->data[head_idx], data, n_chunk);
632 clib_memcpy_fast (&c->next->data[0], data + n_chunk, len - n_chunk);
Florin Coras7fb0fe12018-04-09 09:24:52 -0700633 }
634}
Florin Coras3aa7af32018-06-29 08:44:31 -0700635#endif
Dave Barach68b0fb02017-02-28 15:15:56 -0500636
Florin Coras0a846802019-04-09 18:29:14 -0700637CLIB_MARCH_FN (svm_fifo_dequeue_nowait, int, svm_fifo_t * f, u32 len,
638 u8 * dst)
Dave Barach68b0fb02017-02-28 15:15:56 -0500639{
Florin Coras0a846802019-04-09 18:29:14 -0700640 u32 to_copy, n_chunk, tail, head, cursize, head_idx;
641 svm_fifo_chunk_t *c;
Dave Barach68b0fb02017-02-28 15:15:56 -0500642
Sirshak Das28aa5392019-02-05 01:33:33 -0600643 f_load_head_tail_cons (f, &head, &tail);
644
645 /* current size of fifo can only increase during dequeue: SPSC */
646 cursize = f_cursize (f, head, tail);
647
Florin Coras3e350af2017-03-30 02:54:28 -0700648 if (PREDICT_FALSE (cursize == 0))
Dave Barach68b0fb02017-02-28 15:15:56 -0500649 return -2; /* nothing in the fifo */
650
Florin Coras0a846802019-04-09 18:29:14 -0700651 to_copy = len = clib_min (cursize, len);
Florin Coras2309e7a2019-04-18 18:58:10 -0700652 ASSERT (cursize >= to_copy);
Dave Barach68b0fb02017-02-28 15:15:56 -0500653
Florin Coras0a846802019-04-09 18:29:14 -0700654 c = f->head_chunk;
Sirshak Das28aa5392019-02-05 01:33:33 -0600655 head_idx = head % f->size;
Florin Coras0a846802019-04-09 18:29:14 -0700656 head_idx -= c->start_byte;
657 n_chunk = c->length - head_idx;
Sirshak Das28aa5392019-02-05 01:33:33 -0600658
Florin Coras0a846802019-04-09 18:29:14 -0700659 if (n_chunk < to_copy)
Dave Barach68b0fb02017-02-28 15:15:56 -0500660 {
Florin Coras0a846802019-04-09 18:29:14 -0700661 clib_memcpy_fast (dst, &c->data[head_idx], n_chunk);
662 while ((to_copy -= n_chunk))
Dave Barach68b0fb02017-02-28 15:15:56 -0500663 {
Florin Coras0a846802019-04-09 18:29:14 -0700664 c = c->next;
665 n_chunk = clib_min (c->length, to_copy);
666 clib_memcpy_fast (dst + (len - to_copy), &c->data[0], n_chunk);
Dave Barach68b0fb02017-02-28 15:15:56 -0500667 }
Florin Coras0a846802019-04-09 18:29:14 -0700668 f->head_chunk = c;
Dave Barach68b0fb02017-02-28 15:15:56 -0500669 }
670 else
671 {
Florin Coras0a846802019-04-09 18:29:14 -0700672 clib_memcpy_fast (dst, &c->data[head_idx], to_copy);
Dave Barach68b0fb02017-02-28 15:15:56 -0500673 }
Florin Coras0a846802019-04-09 18:29:14 -0700674 head += len;
Dave Barach68b0fb02017-02-28 15:15:56 -0500675
Florin Coras2309e7a2019-04-18 18:58:10 -0700676 if (PREDICT_FALSE (f->flags & SVM_FIFO_F_SIZE_UPDATE))
677 svm_fifo_try_size_update (f, head);
678
Sirshak Das28aa5392019-02-05 01:33:33 -0600679 /* store-rel: consumer owned index (paired with load-acq in producer) */
680 clib_atomic_store_rel_n (&f->head, head);
Dave Barach68b0fb02017-02-28 15:15:56 -0500681
Florin Coras0a846802019-04-09 18:29:14 -0700682 return len;
Dave Barach68b0fb02017-02-28 15:15:56 -0500683}
684
Florin Coras3aa7af32018-06-29 08:44:31 -0700685#ifndef CLIB_MARCH_VARIANT
Florin Corasf6359c82017-06-19 12:26:09 -0400686
Dave Barach68b0fb02017-02-28 15:15:56 -0500687int
Florin Corasf6359c82017-06-19 12:26:09 -0400688svm_fifo_dequeue_nowait (svm_fifo_t * f, u32 max_bytes, u8 * copy_here)
689{
Florin Coras983cc7d2018-09-18 23:11:55 -0700690 return CLIB_MARCH_FN_SELECT (svm_fifo_dequeue_nowait) (f, max_bytes,
691 copy_here);
Florin Corasf6359c82017-06-19 12:26:09 -0400692}
Florin Coras3aa7af32018-06-29 08:44:31 -0700693#endif
Florin Corasf6359c82017-06-19 12:26:09 -0400694
Florin Coras983cc7d2018-09-18 23:11:55 -0700695CLIB_MARCH_FN (svm_fifo_peek, int, svm_fifo_t * f, u32 relative_offset,
Florin Coras0a846802019-04-09 18:29:14 -0700696 u32 len, u8 * dst)
Dave Barach68b0fb02017-02-28 15:15:56 -0500697{
Florin Coras0a846802019-04-09 18:29:14 -0700698 u32 to_copy, n_chunk, tail, head, cursize, head_idx;
699 svm_fifo_chunk_t *c;
Dave Barach68b0fb02017-02-28 15:15:56 -0500700
Sirshak Das28aa5392019-02-05 01:33:33 -0600701 f_load_head_tail_cons (f, &head, &tail);
702
703 /* current size of fifo can only increase during peek: SPSC */
704 cursize = f_cursize (f, head, tail);
705
Florin Coras93992a92017-05-24 18:03:56 -0700706 if (PREDICT_FALSE (cursize < relative_offset))
Dave Barach68b0fb02017-02-28 15:15:56 -0500707 return -2; /* nothing in the fifo */
708
Florin Coras0a846802019-04-09 18:29:14 -0700709 to_copy = len = clib_min (cursize - relative_offset, len);
Dave Barach68b0fb02017-02-28 15:15:56 -0500710
Florin Coras0a846802019-04-09 18:29:14 -0700711 c = f->head_chunk;
712 head_idx = (head + relative_offset) % f->size;
713 head_idx -= c->start_byte;
714 n_chunk = c->length - head_idx;
Dave Barach68b0fb02017-02-28 15:15:56 -0500715
Florin Coras0a846802019-04-09 18:29:14 -0700716 if (n_chunk < to_copy)
Dave Barach68b0fb02017-02-28 15:15:56 -0500717 {
Florin Coras0a846802019-04-09 18:29:14 -0700718 clib_memcpy_fast (dst, &c->data[head_idx], n_chunk);
719 while ((to_copy -= n_chunk))
Dave Barach68b0fb02017-02-28 15:15:56 -0500720 {
Florin Coras0a846802019-04-09 18:29:14 -0700721 c = c->next;
722 n_chunk = clib_min (c->length, to_copy);
723 clib_memcpy_fast (dst + (len - to_copy), &c->data[0], n_chunk);
Dave Barach68b0fb02017-02-28 15:15:56 -0500724 }
Florin Coras0a846802019-04-09 18:29:14 -0700725 f->head_chunk = c;
Dave Barach68b0fb02017-02-28 15:15:56 -0500726 }
Florin Coras0a846802019-04-09 18:29:14 -0700727 else
728 {
729 clib_memcpy_fast (dst, &c->data[head_idx], to_copy);
730 }
731 return len;
Dave Barach68b0fb02017-02-28 15:15:56 -0500732}
733
Florin Coras3aa7af32018-06-29 08:44:31 -0700734#ifndef CLIB_MARCH_VARIANT
Florin Corasf6359c82017-06-19 12:26:09 -0400735
736int
737svm_fifo_peek (svm_fifo_t * f, u32 relative_offset, u32 max_bytes,
738 u8 * copy_here)
739{
Florin Coras983cc7d2018-09-18 23:11:55 -0700740 return CLIB_MARCH_FN_SELECT (svm_fifo_peek) (f, relative_offset, max_bytes,
741 copy_here);
Florin Corasf6359c82017-06-19 12:26:09 -0400742}
743
Dave Barach68b0fb02017-02-28 15:15:56 -0500744int
Florin Corasa5464812017-04-19 13:00:05 -0700745svm_fifo_dequeue_drop (svm_fifo_t * f, u32 max_bytes)
Dave Barach68b0fb02017-02-28 15:15:56 -0500746{
Sirshak Das28aa5392019-02-05 01:33:33 -0600747 u32 total_drop_bytes;
748 u32 tail, head, cursize;
Dave Barach68b0fb02017-02-28 15:15:56 -0500749
Sirshak Das28aa5392019-02-05 01:33:33 -0600750 f_load_head_tail_cons (f, &head, &tail);
751
752 /* number of bytes we're going to drop */
753 cursize = f_cursize (f, head, tail);
754
Florin Coras3e350af2017-03-30 02:54:28 -0700755 if (PREDICT_FALSE (cursize == 0))
Dave Barach68b0fb02017-02-28 15:15:56 -0500756 return -2; /* nothing in the fifo */
757
Sirshak Das28aa5392019-02-05 01:33:33 -0600758 svm_fifo_trace_add (f, tail, total_drop_bytes, 3);
Dave Barach68b0fb02017-02-28 15:15:56 -0500759
Sirshak Das28aa5392019-02-05 01:33:33 -0600760 /* number of bytes we're going to drop */
Dave Barach68b0fb02017-02-28 15:15:56 -0500761 total_drop_bytes = (cursize < max_bytes) ? cursize : max_bytes;
762
Sirshak Das28aa5392019-02-05 01:33:33 -0600763 /* move head */
764 head += total_drop_bytes;
Florin Coras3eb50622017-07-13 01:24:57 -0400765
Dave Barach2c25a622017-06-26 11:35:07 -0400766 ASSERT (cursize >= total_drop_bytes);
Sirshak Das28aa5392019-02-05 01:33:33 -0600767 /* store-rel: consumer owned index (paired with load-acq in producer) */
768 clib_atomic_store_rel_n (&f->head, head);
Dave Barach68b0fb02017-02-28 15:15:56 -0500769
770 return total_drop_bytes;
771}
772
Florin Coras25579b42018-06-06 17:55:02 -0700773void
774svm_fifo_dequeue_drop_all (svm_fifo_t * f)
775{
Sirshak Das28aa5392019-02-05 01:33:33 -0600776 /* consumer foreign index */
777 u32 tail = clib_atomic_load_acq_n (&f->tail);
778 /* store-rel: consumer owned index (paired with load-acq in producer) */
779 clib_atomic_store_rel_n (&f->head, tail);
Florin Coras25579b42018-06-06 17:55:02 -0700780}
781
Florin Coras2cba8532018-09-11 16:33:36 -0700782int
783svm_fifo_segments (svm_fifo_t * f, svm_fifo_segment_t * fs)
784{
Sirshak Das28aa5392019-02-05 01:33:33 -0600785 u32 cursize, head, tail, head_idx;
Florin Coras2cba8532018-09-11 16:33:36 -0700786
Sirshak Das28aa5392019-02-05 01:33:33 -0600787 f_load_head_tail_cons (f, &head, &tail);
788
789 /* consumer function, cursize can only increase while we're working */
790 cursize = f_cursize (f, head, tail);
791
Florin Coras2cba8532018-09-11 16:33:36 -0700792 if (PREDICT_FALSE (cursize == 0))
Sirshak Das28aa5392019-02-05 01:33:33 -0600793 return -2; /* nothing in the fifo */
Florin Coras2cba8532018-09-11 16:33:36 -0700794
Sirshak Das28aa5392019-02-05 01:33:33 -0600795 head_idx = head % f->size;
Florin Coras2cba8532018-09-11 16:33:36 -0700796
Sirshak Das28aa5392019-02-05 01:33:33 -0600797 if (tail < head)
Florin Coras2cba8532018-09-11 16:33:36 -0700798 {
Sirshak Das28aa5392019-02-05 01:33:33 -0600799 fs[0].len = f->size - head_idx;
Florin Coras0a846802019-04-09 18:29:14 -0700800 fs[0].data = f->head_chunk->data + head_idx;
Florin Coras2cba8532018-09-11 16:33:36 -0700801 fs[1].len = cursize - fs[0].len;
Florin Coras0a846802019-04-09 18:29:14 -0700802 fs[1].data = f->head_chunk->data;
Florin Coras2cba8532018-09-11 16:33:36 -0700803 }
804 else
805 {
Sirshak Das28aa5392019-02-05 01:33:33 -0600806 fs[0].len = cursize;
Florin Coras0a846802019-04-09 18:29:14 -0700807 fs[0].data = f->head_chunk->data + head_idx;
Florin Coras2cba8532018-09-11 16:33:36 -0700808 fs[1].len = 0;
809 fs[1].data = 0;
810 }
811 return cursize;
812}
813
814void
815svm_fifo_segments_free (svm_fifo_t * f, svm_fifo_segment_t * fs)
816{
Sirshak Das28aa5392019-02-05 01:33:33 -0600817 u32 head, head_idx;
Florin Coras2cba8532018-09-11 16:33:36 -0700818
Sirshak Das28aa5392019-02-05 01:33:33 -0600819 /* consumer owned index */
820 head = f->head;
821 head_idx = head % f->size;
822
Florin Coras0a846802019-04-09 18:29:14 -0700823 ASSERT (fs[0].data == f->head_chunk->data + head_idx);
Sirshak Das28aa5392019-02-05 01:33:33 -0600824 head += fs[0].len + fs[1].len;
825 /* store-rel: consumer owned index (paired with load-acq in producer) */
826 clib_atomic_store_rel_n (&f->head, head);
827}
828
829/* Assumption: no prod and cons are accessing either dest or src fifo */
830void
831svm_fifo_clone (svm_fifo_t * df, svm_fifo_t * sf)
832{
833 u32 head, tail;
Florin Coras0a846802019-04-09 18:29:14 -0700834 clib_memcpy_fast (df->head_chunk->data, sf->head_chunk->data, sf->size);
Sirshak Das28aa5392019-02-05 01:33:33 -0600835
836 f_load_head_tail_all_acq (sf, &head, &tail);
837 clib_atomic_store_rel_n (&df->head, head);
838 clib_atomic_store_rel_n (&df->tail, tail);
Florin Coras2cba8532018-09-11 16:33:36 -0700839}
840
Dave Barach1f75cfd2017-04-14 16:46:44 -0400841u32
842svm_fifo_number_ooo_segments (svm_fifo_t * f)
843{
844 return pool_elts (f->ooo_segments);
845}
846
847ooo_segment_t *
848svm_fifo_first_ooo_segment (svm_fifo_t * f)
849{
850 return pool_elt_at_index (f->ooo_segments, f->ooos_list_head);
851}
852
Florin Corasc28764f2017-04-26 00:08:42 -0700853/**
854 * Set fifo pointers to requested offset
855 */
856void
857svm_fifo_init_pointers (svm_fifo_t * f, u32 pointer)
858{
Sirshak Das28aa5392019-02-05 01:33:33 -0600859 clib_atomic_store_rel_n (&f->head, pointer);
860 clib_atomic_store_rel_n (&f->tail, pointer);
Florin Corasc28764f2017-04-26 00:08:42 -0700861}
862
Florin Coras72b04282019-01-14 17:23:11 -0800863void
864svm_fifo_add_subscriber (svm_fifo_t * f, u8 subscriber)
865{
866 if (f->n_subscribers >= SVM_FIFO_MAX_EVT_SUBSCRIBERS)
867 return;
868 f->subscribers[f->n_subscribers++] = subscriber;
869}
870
871void
872svm_fifo_del_subscriber (svm_fifo_t * f, u8 subscriber)
873{
874 int i;
875
876 for (i = 0; i < f->n_subscribers; i++)
877 {
878 if (f->subscribers[i] != subscriber)
879 continue;
880 f->subscribers[i] = f->subscribers[f->n_subscribers - 1];
881 f->n_subscribers--;
882 break;
883 }
884}
885
Florin Coras3aa7af32018-06-29 08:44:31 -0700886#endif
Dave Barach68b0fb02017-02-28 15:15:56 -0500887/*
888 * fd.io coding-style-patch-verification: ON
889 *
890 * Local Variables:
891 * eval: (c-set-style "gnu")
892 * End:
893 */