svm: fifo segment support for chunk allocation
[vpp.git] / src / svm / fifo_segment.c
index 6bf2634..9c332d6 100644 (file)
@@ -237,7 +237,7 @@ fs_free_list_for_size (u32 size)
 }
 
 static inline int
-fs_fifo_size_is_valid (u32 size)
+fs_chunk_size_is_valid (u32 size)
 {
   /*
    * 4K minimum. It's not likely that anything good will happen
@@ -293,7 +293,7 @@ fifo_segment_alloc_fifo (fifo_segment_t * fs, u32 data_bytes,
   void *oldheap;
   int fl_index;
 
-  if (!fs_fifo_size_is_valid (data_bytes))
+  if (!fs_chunk_size_is_valid (data_bytes))
     {
       clib_warning ("fifo size out of range %d", data_bytes);
       return 0;
@@ -304,7 +304,7 @@ fifo_segment_alloc_fifo (fifo_segment_t * fs, u32 data_bytes,
   sh = fs->ssvm.sh;
   ssvm_lock_non_recursive (sh, 1);
 
-  fsh = (fifo_segment_header_t *) sh->opaque[0];
+  fsh = fs->h;
   vec_validate_init_empty (fsh->free_fifos, fl_index, 0);
   f = fsh->free_fifos[fl_index];
 
@@ -363,7 +363,7 @@ done:
  * Free fifo allocated in fifo segment
  */
 void
-fifo_segment_free_fifo (fifo_segment_t * s, svm_fifo_t * f)
+fifo_segment_free_fifo (fifo_segment_t * fs, svm_fifo_t * f)
 {
   fifo_segment_header_t *fsh;
   ssvm_shared_header_t *sh;
@@ -374,8 +374,8 @@ fifo_segment_free_fifo (fifo_segment_t * s, svm_fifo_t * f)
   if (--f->refcnt > 0)
     return;
 
-  sh = s->ssvm.sh;
-  fsh = (fifo_segment_header_t *) sh->opaque[0];
+  sh = fs->ssvm.sh;
+  fsh = fs->h;
   fl_index = f->freelist_index;
 
   ASSERT (fl_index < vec_len (fsh->free_fifos));
@@ -399,6 +399,29 @@ fifo_segment_free_fifo (fifo_segment_t * s, svm_fifo_t * f)
   f->prev = 0;
   fsh->free_fifos[fl_index] = f;
 
+  /* If fifo has more chunks, free them */
+  if (f->flags & SVM_FIFO_F_MULTI_CHUNK)
+    {
+      svm_fifo_chunk_t *cur, *next;
+      void *oldheap;
+
+      next = f->start_chunk->next;
+      while (next != f->start_chunk)
+       {
+         cur = next;
+         next = next->next;
+         fl_index = fs_free_list_for_size (cur->length);
+         cur->next = fsh->free_chunks[fl_index];
+         fsh->free_chunks[fl_index] = cur;
+       }
+      oldheap = ssvm_push_heap (sh);
+      svm_fifo_free_chunk_lookup (f);
+      ssvm_pop_heap (oldheap);
+    }
+
+  /* not allocated on segment heap */
+  svm_fifo_free_ooo_data (f);
+
   if (CLIB_DEBUG)
     {
       f->master_session_index = ~0;
@@ -431,13 +454,13 @@ fifo_segment_preallocate_fifo_pairs (fifo_segment_t * fs,
   if (rx_fifo_size == 0 || tx_fifo_size == 0 || *n_fifo_pairs == 0)
     return;
 
-  if (!fs_fifo_size_is_valid (rx_fifo_size))
+  if (!fs_chunk_size_is_valid (rx_fifo_size))
     {
       clib_warning ("rx fifo_size out of range %d", rx_fifo_size);
       return;
     }
 
-  if (!fs_fifo_size_is_valid (tx_fifo_size))
+  if (!fs_chunk_size_is_valid (tx_fifo_size))
     {
       clib_warning ("tx fifo_size out of range %d", tx_fifo_size);
       return;
@@ -502,6 +525,51 @@ fifo_segment_preallocate_fifo_pairs (fifo_segment_t * fs,
   ssvm_pop_heap (oldheap);
 }
 
+int
+fifo_segment_grow_fifo (fifo_segment_t * fs, svm_fifo_t * f, u32 chunk_size)
+{
+  ssvm_shared_header_t *sh;
+  svm_fifo_chunk_t *c;
+  void *oldheap;
+  int fl_index;
+
+  if (!fs_chunk_size_is_valid (chunk_size))
+    {
+      clib_warning ("chunk size out of range %d", chunk_size);
+      return 0;
+    }
+
+  fl_index = fs_free_list_for_size (chunk_size);
+
+  sh = fs->ssvm.sh;
+  ssvm_lock_non_recursive (sh, 1);
+
+  vec_validate_init_empty (fs->h->free_chunks, fl_index, 0);
+  c = fs->h->free_chunks[fl_index];
+
+  oldheap = ssvm_push_heap (sh);
+
+  if (!c)
+    {
+      c = svm_fifo_chunk_alloc (chunk_size);
+      if (!c)
+       {
+         ssvm_pop_heap (oldheap);
+         return -1;
+       }
+    }
+  else
+    {
+      fs->h->free_chunks[fl_index] = c->next;
+    }
+
+  svm_fifo_add_chunk (f, c);
+
+  ssvm_pop_heap (oldheap);
+  ssvm_unlock_non_recursive (sh);
+  return 0;
+}
+
 /**
  * Get number of active fifos
  */
@@ -559,6 +627,52 @@ fifo_segment_num_free_fifos (fifo_segment_t * fs, u32 fifo_size_in_bytes)
   return count;
 }
 
+u32
+fifo_segment_num_free_chunks (fifo_segment_t * fs, u32 size)
+{
+  u32 count = 0, rounded_size, fl_index;
+  fifo_segment_header_t *fsh;
+  svm_fifo_chunk_t *c;
+  int i;
+
+  fsh = fs->h;
+
+  /* Count all free chunks? */
+  if (size == ~0)
+    {
+      for (i = 0; i < vec_len (fsh->free_chunks); i++)
+       {
+         c = fsh->free_chunks[i];
+         if (c == 0)
+           continue;
+
+         while (c)
+           {
+             c = c->next;
+             count++;
+           }
+       }
+      return count;
+    }
+
+  rounded_size = (1 << (max_log2 (size)));
+  fl_index = fs_free_list_for_size (rounded_size);
+
+  if (fl_index >= vec_len (fsh->free_chunks))
+    return 0;
+
+  c = fsh->free_chunks[fl_index];
+  if (c == 0)
+    return 0;
+
+  while (c)
+    {
+      c = c->next;
+      count++;
+    }
+  return count;
+}
+
 u8
 fifo_segment_has_fifos (fifo_segment_t * fs)
 {