All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mpfifo.h
Go to the documentation of this file.
1 #pragma once
2 
3 // 2-7-2013 : Changed ASSERT to exit(-1) and printf functrion due to compatibility issues
4 
5 #include <cvmx-spinlock.h>
6 #include <cvmx-bootmem.h>
7 #include <cvmx-fpa.h>
8 #include <cvmx-rng.h>
9 #include <algorithm>
10 //#include "coremask.h"
11 
12 // Creates a unlocked fifo that can be used for
13 // Cavium simple exe programs
14 template <class T>
15 class CMpFifo
16 {
17 public:
18  struct TPointers
19  {
24  uint32_t ulSize; // size in items
26  cvmx_spinlock_t tLock;
27  };
28 
29  void Init ( uint32_t ulNrOfItems, char *pMemName = NULL );
30  T* Init (uint32_t ulNrOfItems, TPointers *ptPointers, uint16_t ui32FPAPool);
31  bool Push ( T &tElement, T* ptFifoArray=NULL, TPointers *ptPointers=NULL);
32  bool Pop ( T *ptElement, T* ptFifoArray=NULL, TPointers *ptPointers=NULL);
33  bool Shuffle ( T* ptFifoArray=NULL, TPointers *ptPointers=NULL);
34  void Close ( T** ptFifoArray=NULL, TPointers *ptPointers=NULL);
35  bool GetItem ( T *ptItem, bool bFirst = false, T* ptFifoArray=NULL, TPointers *ptPointers=NULL);
36  uint32_t NrOfItems (TPointers *ptPointers=NULL);
37 
38 private:
39  CCoremask m_cCoremask;
40  T* m_ptFifoArray;
41  TPointers *m_ptPointers;
42  char m_cMemName[80];
43 
44  static int Random_Function(int j);
45 };
46 
47 // Allocates memory for the shared
48 // fifo. One core should call alloc
49 //
50 template <class T>
51 void CMpFifo<T>::Init(uint32_t ulNrOfItems, char *pMemName )
52 {
53  if (pMemName)
54  {
55  strcpy(m_cMemName, pMemName);
56  }
57  else
58  {
59  strcpy(m_cMemName, "mpFifoMemory");
60  }
61 
62  m_cCoremask.Set();
63 
64  m_ptPointers = (TPointers *) cvmx_bootmem_alloc_named(sizeof(TPointers) + ulNrOfItems * sizeof(T), CVMX_CACHE_LINE_SIZE, m_cMemName);
65  if (m_ptPointers == NULL)
66  {
67  if (cvmx_bootmem_find_named_block(m_cMemName))
68  {
69  m_ptPointers = (TPointers *)cvmx_phys_to_ptr(cvmx_bootmem_find_named_block(m_cMemName)->base_addr);
70  if (m_ptPointers == NULL)
71  {
72  printf("CMpFifo::Could not attach to FifoMemory\n");
73  return;
74  }
75  m_ptFifoArray = (T *)(m_ptPointers + 1);
76  }
77  }
78  else
79  {
80  m_ptFifoArray = (T *)(m_ptPointers + 1);
81 
82  m_ptPointers->ulSize = ulNrOfItems;
83  m_ptPointers->ulItems = 0;
84  m_ptPointers->ulWrite = 0;
85  m_ptPointers->ulRead = 0;
86  cvmx_spinlock_init(&m_ptPointers->tLock);
87  }
88  // We need the random number generator, so enable it
89  cvmx_rng_enable();
90 
91  m_cCoremask.BarrierSync();
92 }
93 
94 //
95 // Random generator is neede by randow_shuffle function
96 template <class T>
98 {
99  return cvmx_rng_get_random32() % j;
100 }
101 
102 template <class T>
103 T* CMpFifo<T>::Init(uint32_t ulNrOfItems, TPointers *ptPointers, uint16_t ui32FPAPool)
104 {
105  uint64_t ui64PoolSize = cvmx_fpa_get_block_size(ui32FPAPool);
106  uint64_t ui64RequiredSpace = ulNrOfItems * sizeof (ulNrOfItems * sizeof (T));
107  if (ui64RequiredSpace >= ui64PoolSize)
108  {
109  printf("Pool %d too small to contain requested data fotr jitter buffer\n", ui32FPAPool);
110  exit(-1);
111  }
112 
113  if (ptPointers == NULL)
114  {
115  printf("CMpFifo::ptFifoMemoryPointers not set\n");
116  return NULL;
117  }
118  T* pt = (T *)cvmx_fpa_alloc(ui32FPAPool);
119  if (pt == NULL)
120  {
121  printf(" CMpFifo::Init::Could not alloc memory from pool %d\n", ui32FPAPool);
122  return NULL;
123  }
124  m_ptPointers = ptPointers;
125 
126  m_ptPointers->ulSize = ulNrOfItems;
127  m_ptPointers->ulItems = 0;
128  m_ptPointers->ulWrite = 0;
129  m_ptPointers->ulRead = 0;
130  m_ptPointers->ulPoolNr = ui32FPAPool;
131  cvmx_spinlock_init(&m_ptPointers->tLock);
132  return pt;
133 }
134 
135 template <class T>
136 bool CMpFifo<T>::Push ( T &tItem, T* ptFifoArray, TPointers *ptPointers)
137 {
138  if (ptPointers)
139  {
140  if (ptFifoArray == NULL)
141  {
142  return false;
143  }
144  m_ptFifoArray = ptFifoArray;
145  m_ptPointers = ptPointers;
146  }
147  cvmx_spinlock_lock(&m_ptPointers->tLock);
148  if (cvmx_unlikely(m_ptPointers->ulItems == m_ptPointers->ulSize))
149  {
150  // full
151  cvmx_spinlock_unlock(&m_ptPointers->tLock);
152  return false;
153  }
154  m_ptPointers->ulItems++;
155  m_ptFifoArray[m_ptPointers->ulWrite] = tItem;
156  m_ptPointers->ulWrite++;
157 
158  if (cvmx_unlikely(m_ptPointers->ulWrite == m_ptPointers->ulSize))
159  {
160  // wrap write pointer
161  m_ptPointers->ulWrite = 0;
162  }
163  CVMX_SYNCWS;
164  cvmx_spinlock_unlock(&m_ptPointers->tLock);
165  return true;
166 }
167 
168 template <class T>
169 bool CMpFifo<T>::Pop( T *ptItem, T* ptFifoArray, TPointers *ptPointers)
170 {
171  if (ptPointers) // If external bookkeeping
172  {
173  m_ptPointers = ptPointers;
174  cvmx_spinlock_lock(&m_ptPointers->tLock);
175  if (ptFifoArray == NULL) // Fifo gone, exit
176  {
177  cvmx_spinlock_unlock(&m_ptPointers->tLock);
178  return false;
179  }
180  m_ptFifoArray = ptFifoArray;
181  }
182  else
183  {
184  cvmx_spinlock_lock(&m_ptPointers->tLock);
185  }
186 
187  if (cvmx_unlikely(m_ptPointers->ulItems == 0))
188  {
189  // empty
190  cvmx_spinlock_unlock(&m_ptPointers->tLock);
191  return false;
192  }
193  *ptItem = m_ptFifoArray[m_ptPointers->ulRead];
194  m_ptPointers->ulRead++;
195  if (cvmx_unlikely(m_ptPointers->ulRead == m_ptPointers->ulSize))
196  {
197  // wrap read pointer
198  m_ptPointers->ulRead = 0;
199  }
200  m_ptPointers->ulItems--;
201  CVMX_SYNCWS;
202  cvmx_spinlock_unlock(&m_ptPointers->tLock);
203  return true;
204 }
205 
206 template <class T>
207 bool CMpFifo<T>::Shuffle( T* ptFifoArray, TPointers *ptPointers)
208 {
209  if (ptPointers) // If external bookkeeping
210  {
211  m_ptPointers = ptPointers;
212  cvmx_spinlock_lock(&m_ptPointers->tLock);
213  if (ptFifoArray == NULL) // Fifo gone, exit
214  {
215  cvmx_spinlock_unlock(&m_ptPointers->tLock);
216  return false;
217  }
218  m_ptFifoArray = ptFifoArray;
219  }
220  else
221  {
222  cvmx_spinlock_lock(&m_ptPointers->tLock);
223  }
224 
225  if (cvmx_unlikely(m_ptPointers->ulItems < 2))
226  {
227  // No need to shuffle
228  cvmx_spinlock_unlock(&m_ptPointers->tLock);
229  return false;
230  }
231 
232  T* ptReadItem = &m_ptFifoArray[m_ptPointers->ulRead];
233  uint32_t ulWriteItem = (m_ptPointers->ulWrite != 0) ? (m_ptPointers->ulWrite - 1) : m_ptPointers->ulSize;
234  T* ptWriteItem = &m_ptFifoArray[ulWriteItem];
235  //printf("Shuffle Size %d, Read %d, Write %d, WritePos %d\n", m_ptPointers->ulSize, m_ptPointers->ulRead, m_ptPointers->ulWrite, ulWriteItem);
236 
237  if (ptReadItem < ptWriteItem)
238  {
239  std::random_shuffle(ptReadItem, ptWriteItem, Random_Function);
240  }
241  else
242  {
243  std::random_shuffle(ptWriteItem, ptReadItem, Random_Function);
244  }
245  CVMX_SYNCWS;
246  cvmx_spinlock_unlock(&m_ptPointers->tLock);
247  return true;
248 }
249 
250 // Dump the contents of the fifo, starting with oldest value. Start calling this function with bFirst = true and repeat calling until it returns false so the spinlock is released
251 template <class T>
252 bool CMpFifo<T>::GetItem( T *ptItem, bool bFirst, T* ptFifoArray, TPointers *ptPointers)
253 {
254  if (bFirst)
255  {
256  if (ptPointers) // If external bookkeeping
257  {
258  m_ptPointers = ptPointers;
259  }
260  cvmx_spinlock_lock(&m_ptPointers->tLock);
261  if (ptPointers && ptFifoArray == NULL) // Fifo gone, exit
262  {
263  cvmx_spinlock_unlock(&m_ptPointers->tLock);
264  return false;
265  }
266 
267  if (m_ptPointers->ulItems == 0)
268  {
269  cvmx_spinlock_unlock(&m_ptPointers->tLock);
270  return false;
271  }
272  m_ptPointers->ulGetPointer = m_ptPointers->ulRead;
273  }
274  if (cvmx_unlikely(m_ptPointers->ulGetPointer == m_ptPointers->ulWrite && !bFirst))
275  {
276  CVMX_SYNCWS;
277  cvmx_spinlock_unlock(&m_ptPointers->tLock);
278  return false;
279  }
280  *ptItem = m_ptFifoArray[m_ptPointers->ulGetPointer];
281  m_ptPointers->ulGetPointer++;
282  if (cvmx_unlikely(m_ptPointers->ulGetPointer == m_ptPointers->ulSize))
283  {
284  // wrap pointer
285  m_ptPointers->ulGetPointer = 0;
286  }
287  CVMX_SYNCWS;
288  return true;
289 }
290 
291 template <class T>
292 void CMpFifo<T>::Close(T** ptFifoArray, TPointers *ptPointers)
293 {
294  if (ptPointers)
295  {
296  m_ptPointers = ptPointers;
297  cvmx_spinlock_lock(&m_ptPointers->tLock);
298  m_ptPointers->ulItems = 0;
299  if (*ptFifoArray == NULL)
300  {
301  printf("CMpFifo::Close::ptFifoArray not set\n");
302  return;
303  }
304  cvmx_fpa_free(*ptFifoArray, m_ptPointers->ulPoolNr, 0);
305  *ptFifoArray = NULL;
306  CVMX_SYNCWS;
307  cvmx_spinlock_unlock(&m_ptPointers->tLock);
308  }
309  else if (m_cCoremask.IsFirstCore())
310  {
311  cvmx_spinlock_lock(&m_ptPointers->tLock);
312  m_ptPointers->ulItems = 0;
313  cvmx_spinlock_unlock(&m_ptPointers->tLock);
314  cvmx_bootmem_free_named(m_cMemName);
315  CVMX_SYNCWS;
316  }
317 }
318 
319 template <class T>
321 {
322  if (ptPointers)
323  {
324  m_ptPointers = ptPointers;
325  }
326  cvmx_spinlock_lock(&m_ptPointers->tLock);
327  uint32_t ui32NrOfItems = m_ptPointers->ulItems;
328  cvmx_spinlock_unlock(&m_ptPointers->tLock);
329  return ui32NrOfItems;
330 }
void Init(uint32_t ulNrOfItems, char *pMemName=NULL)
Definition: mpfifo.h:51
uint32_t ulWrite
Definition: mpfifo.h:21
uint32_t ulItems
Definition: mpfifo.h:22
Definition: mpfifo.h:15
uint32_t ulSize
Definition: mpfifo.h:24
uint32_t ulRead
Definition: mpfifo.h:20
uint32_t NrOfItems(TPointers *ptPointers=NULL)
Definition: mpfifo.h:320
bool Push(T &tElement, T *ptFifoArray=NULL, TPointers *ptPointers=NULL)
Definition: mpfifo.h:136
bool Shuffle(T *ptFifoArray=NULL, TPointers *ptPointers=NULL)
Definition: mpfifo.h:207
void Close(T **ptFifoArray=NULL, TPointers *ptPointers=NULL)
Definition: mpfifo.h:292
uint32_t ulPoolNr
Definition: mpfifo.h:25
uint32_t ulGetPointer
Definition: mpfifo.h:23
cvmx_spinlock_t tLock
Definition: mpfifo.h:26
bool GetItem(T *ptItem, bool bFirst=false, T *ptFifoArray=NULL, TPointers *ptPointers=NULL)
Definition: mpfifo.h:252
bool Pop(T *ptElement, T *ptFifoArray=NULL, TPointers *ptPointers=NULL)
Definition: mpfifo.h:169