+static void
+allocate_new_fifo_chunk (svm_fifo_segment_header_t * fsh,
+ u32 data_size_in_bytes, int chunk_size)
+{
+ int freelist_index;
+ u32 size;
+ u8 *fifo_space;
+ u32 rounded_data_size;
+ svm_fifo_t *f;
+ int i;
+
+ rounded_data_size = (1 << (max_log2 (data_size_in_bytes)));
+ freelist_index = max_log2 (rounded_data_size)
+ - max_log2 (FIFO_SEGMENT_MIN_FIFO_SIZE);
+
+ /* Calculate space requirement $$$ round-up data_size_in_bytes */
+ size = (sizeof (*f) + rounded_data_size) * chunk_size;
+
+ /* Allocate fifo space. May fail. */
+ fifo_space = clib_mem_alloc_aligned_at_offset
+ (size, CLIB_CACHE_LINE_BYTES, 0 /* align_offset */ ,
+ 0 /* os_out_of_memory */ );
+
+ /* Out of space.. */
+ if (fifo_space == 0)
+ return;
+
+ /* Carve fifo space */
+ f = (svm_fifo_t *) fifo_space;
+ for (i = 0; i < chunk_size; i++)
+ {
+ f->freelist_index = freelist_index;
+ f->next = fsh->free_fifos[freelist_index];
+ fsh->free_fifos[freelist_index] = f;
+ fifo_space += sizeof (*f) + rounded_data_size;
+ f = (svm_fifo_t *) fifo_space;
+ }
+}
+
+/**
+ * Pre-allocates fifo pairs in fifo segment
+ *
+ * The number of fifos pre-allocated is the minimum of the requested number
+ * of pairs and the maximum number that fit within the segment. If the maximum
+ * is hit, the number of fifo pairs requested is updated by subtracting the
+ * number of fifos that have been successfully allocated.
+ */
+void
+svm_fifo_segment_preallocate_fifo_pairs (svm_fifo_segment_private_t * s,
+ u32 rx_fifo_size, u32 tx_fifo_size,
+ u32 * n_fifo_pairs)
+{
+ u32 rx_rounded_data_size, tx_rounded_data_size, pair_size;
+ u32 rx_fifos_size, tx_fifos_size, pairs_to_allocate;
+ int rx_freelist_index, tx_freelist_index;
+ ssvm_shared_header_t *sh = s->ssvm.sh;
+ svm_fifo_segment_header_t *fsh = s->h;
+ u8 *rx_fifo_space, *tx_fifo_space;
+ uword space_available;
+ void *oldheap;
+ svm_fifo_t *f;
+ int i;
+
+ /* Parameter check */
+ if (rx_fifo_size == 0 || tx_fifo_size == 0 || *n_fifo_pairs == 0)
+ return;
+
+ if (rx_fifo_size < FIFO_SEGMENT_MIN_FIFO_SIZE ||
+ rx_fifo_size > FIFO_SEGMENT_MAX_FIFO_SIZE)
+ {
+ clib_warning ("rx fifo_size out of range %d", rx_fifo_size);
+ return;
+ }
+
+ if (tx_fifo_size < FIFO_SEGMENT_MIN_FIFO_SIZE ||
+ tx_fifo_size > FIFO_SEGMENT_MAX_FIFO_SIZE)
+ {
+ clib_warning ("tx fifo_size out of range %d", rx_fifo_size);
+ return;
+ }
+
+ rx_rounded_data_size = (1 << (max_log2 (rx_fifo_size)));
+ rx_freelist_index = max_log2 (rx_fifo_size)
+ - max_log2 (FIFO_SEGMENT_MIN_FIFO_SIZE);
+ tx_rounded_data_size = (1 << (max_log2 (tx_fifo_size)));
+ tx_freelist_index = max_log2 (tx_fifo_size)
+ - max_log2 (FIFO_SEGMENT_MIN_FIFO_SIZE);
+
+ /* Calculate space requirements */
+ pair_size = 2 * sizeof (*f) + rx_rounded_data_size + tx_rounded_data_size;
+#if USE_DLMALLOC == 0
+ space_available = s->ssvm.ssvm_size - mheap_bytes (sh->heap);
+#else
+ space_available = s->ssvm.ssvm_size - mspace_usable_size (sh->heap);
+#endif
+
+ pairs_to_allocate = clib_min (space_available / pair_size, *n_fifo_pairs);
+ rx_fifos_size = (sizeof (*f) + rx_rounded_data_size) * pairs_to_allocate;
+ tx_fifos_size = (sizeof (*f) + tx_rounded_data_size) * pairs_to_allocate;
+
+ vec_validate_init_empty (fsh->free_fifos,
+ clib_max (rx_freelist_index, tx_freelist_index),
+ 0);
+
+ oldheap = ssvm_push_heap (sh);
+ /* Allocate rx fifo space. May fail. */
+ rx_fifo_space = clib_mem_alloc_aligned_at_offset
+ (rx_fifos_size, CLIB_CACHE_LINE_BYTES, 0 /* align_offset */ ,
+ 0 /* os_out_of_memory */ );
+
+ /* Same for TX */
+ tx_fifo_space = clib_mem_alloc_aligned_at_offset
+ (tx_fifos_size, CLIB_CACHE_LINE_BYTES, 0 /* align_offset */ ,
+ 0 /* os_out_of_memory */ );
+
+ /* Make sure it worked. Clean up if it didn't... */
+ if (rx_fifo_space == 0 || tx_fifo_space == 0)
+ {
+ if (rx_fifo_space)
+ clib_mem_free (rx_fifo_space);
+ else
+ clib_warning ("rx fifo preallocation failure: size %d npairs %d",
+ rx_fifo_size, *n_fifo_pairs);
+
+ if (tx_fifo_space)
+ clib_mem_free (tx_fifo_space);
+ else
+ clib_warning ("tx fifo preallocation failure: size %d nfifos %d",
+ tx_fifo_size, *n_fifo_pairs);
+ ssvm_pop_heap (oldheap);
+ return;
+ }
+
+ /* Carve rx fifo space */
+ f = (svm_fifo_t *) rx_fifo_space;
+ for (i = 0; i < pairs_to_allocate; i++)
+ {
+ f->freelist_index = rx_freelist_index;
+ f->next = fsh->free_fifos[rx_freelist_index];
+ fsh->free_fifos[rx_freelist_index] = f;
+ rx_fifo_space += sizeof (*f) + rx_rounded_data_size;
+ f = (svm_fifo_t *) rx_fifo_space;
+ }
+ /* Carve tx fifo space */
+ f = (svm_fifo_t *) tx_fifo_space;
+ for (i = 0; i < pairs_to_allocate; i++)
+ {
+ f->freelist_index = tx_freelist_index;
+ f->next = fsh->free_fifos[tx_freelist_index];
+ fsh->free_fifos[tx_freelist_index] = f;
+ tx_fifo_space += sizeof (*f) + tx_rounded_data_size;
+ f = (svm_fifo_t *) tx_fifo_space;
+ }
+
+ /* Account for the pairs allocated */
+ *n_fifo_pairs -= pairs_to_allocate;
+ ssvm_pop_heap (oldheap);
+}
+
+/**
+ * Initialize svm fifo segment shared header
+ */