FAPI TM, WLS_LIB and ODULOW documentation
[o-du/phy.git] / wls_lib / test / fapi / fapi_main.c
1 /******************************************************************************
2 *
3 *   Copyright (c) 2019 Intel.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 *
17 *******************************************************************************/
18
19 /**
20  * @brief This file is test FAPI wls lib main process
21  * @file fapi_main.c
22  * @ingroup group_testfapiwls
23  * @author Intel Corporation
24  **/
25
26
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include <rte_eal.h>
33 #include <rte_cfgfile.h>
34 #include <rte_string_fns.h>
35 #include <rte_common.h>
36 #include <rte_string_fns.h>
37 #include <rte_lcore.h>
38 #include <rte_debug.h>
39 #include <rte_launch.h>
40
41 #define DPDK_WLS
42 #include "wls.h"
43 #include "wls_lib.h"
44
45 #define NR5G_FAPI2PHY_WLS_INST 0
46 #define NR5G_FAPI2MAC_WLS_INST 1
47 #define SUCCESS 0
48 #define FAILURE 1
49 #define WLS_TEST_DEV_NAME "wls"
50 #define WLS_TEST_MSG_ID   1
51 #define WLS_TEST_MSG_SIZE 100
52 #define WLS_TEST_MEM_SIZE 2126512128 
53 #define ALLOC_TRACK_SIZE 16384
54 #define MIN_UL_BUF_LOCATIONS 50
55 #define MIN_DL_BUF_LOCATIONS 50
56 #define MAX_UL_BUF_LOCATIONS 50
57 #define MAX_DL_BUF_LOCATIONS 50
58 #define NUM_WLS_INSTANCES 2
59 #define WLS_HUGE_DEF_PAGE_SIZEA    0x40000000LL
60 #define MSG_MAXSIZE1 (16*16384)
61 #define NUM_TEST_MSGS   16
62
63
64
65
66 typedef void* WLS_HANDLE;
67 typedef struct wls_fapi_mem_array
68 {
69     void **ppFreeBlock;
70     void *pStorage;
71     void *pEndOfStorage;
72     uint32_t nBlockSize;
73     uint32_t nBlockCount;
74 } WLS_FAPI_MEM_STRUCT, *PWLS_FAPI_MEM_STRUCT;
75
76 // WLS context structure
77 typedef struct _nr5g_fapi_wls_context {
78     void        *shmem;       // shared  memory region.
79     uint64_t    shmem_size;   // shared  memory region size.
80     WLS_FAPI_MEM_STRUCT sWlsStruct;
81     WLS_HANDLE  h_wls[NUM_WLS_INSTANCES]; // WLS context handle
82     void *pWlsMemBase;
83     uint32_t nTotalMemorySize;
84     uint32_t nTotalBlocks;
85     uint32_t nAllocBlocks;
86     uint32_t nTotalAllocCnt;
87     uint32_t nTotalFreeCnt;
88     uint32_t nTotalUlBufAllocCnt;
89     uint32_t nTotalUlBufFreeCnt;
90     uint32_t nTotalDlBufAllocCnt;
91     uint32_t nTotalDlBufFreeCnt;
92     uint32_t nPartitionMemSize;
93     void     *pPartitionMemBase;
94     volatile pthread_mutex_t lock;
95     volatile pthread_mutex_t lock_alloc;
96 } nr5g_fapi_wls_context_t, *p_nr5g_fapi_wls_context_t;
97
98 nr5g_fapi_wls_context_t  g_wls_ctx;
99 typedef void* WLS_HANDLE;
100 static uint8_t alloc_track[ALLOC_TRACK_SIZE];
101 void *g_shmem;
102 uint32_t g_shmem_size=0;
103 uint32_t g_nTotalAllocCnt=0;
104 uint32_t g_nAllocBlocks=0;
105 uint32_t gwls_fapi_ready=0;
106 WLS_FAPI_MEM_STRUCT g_MemArray;
107 nr5g_fapi_wls_context_t  g_wls_ctx;
108 uint32_t g_nTotalDlBufAllocCnt=0;
109 uint32_t g_nTotalUlBufAllocCnt=0;
110
111 wls_us_ctx_t gphy_wls;
112 wls_us_ctx_t gfapi_wls;
113
114 WLS_HANDLE   g_phy_wls = &gphy_wls;
115 WLS_HANDLE   g_fapi_wls = &gfapi_wls;
116
117 uint8_t    fapi_dpdk_init(void);
118 uint8_t    fapi_wls_init(const char *dev_name, unsigned long long mem_size);
119 uint64_t   fapi_mac_recv();
120 uint8_t    fapi_phy_send();
121 uint64_t   fapi_phy_recv();
122 uint8_t    fapi_mac_send();
123 uint8_t    fapi2Phy_wls_init(p_nr5g_fapi_wls_context_t pwls);
124 uint8_t wls_fapi_create_partition(p_nr5g_fapi_wls_context_t pWls);
125 uint32_t wls_fapi_alloc_mem_array(PWLS_FAPI_MEM_STRUCT pMemArray, void **ppBlock);
126 uint32_t wls_fapi_create_mem_array(PWLS_FAPI_MEM_STRUCT pMemArray, void *pMemArrayMemory, uint32_t totalSize, uint32_t nBlockSize);
127
128 uint64_t nr5g_fapi_wls_va_to_pa(WLS_HANDLE h_wls, void *ptr)
129 {
130     return ((uint64_t)WLS_VA2PA(h_wls, ptr));
131 }
132
133 inline p_nr5g_fapi_wls_context_t nr5g_fapi_wls_context()
134 {
135     return &g_wls_ctx;
136 }
137
138 static inline WLS_HANDLE nr5g_fapi_fapi2mac_wls_instance()
139 {
140     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
141
142     return p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST];
143 }
144
145 static inline WLS_HANDLE nr5g_fapi_fapi2phy_wls_instance()
146 {
147     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
148     return p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST];
149 }
150 void *wls_fapi_alloc_buffer(uint32_t size, uint32_t loc)
151 {
152     void *pBlock = NULL;
153     p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
154     PWLS_FAPI_MEM_STRUCT pMemArray = &pWls->sWlsStruct;
155
156     pthread_mutex_lock((pthread_mutex_t *)&pWls->lock_alloc);
157
158     if (wls_fapi_alloc_mem_array(&pWls->sWlsStruct, &pBlock) != SUCCESS)
159     {
160         printf("wls_fapi_alloc_buffer alloc error size[%d] loc[%d]\n", size, loc);
161
162         exit(-1);
163     }
164     else
165     {
166         pWls->nAllocBlocks++;
167     }
168
169     //printf("----------------wls_fapi_alloc_buffer: size[%d] loc[%d] buf[%p] nAllocBlocks[%d]\n", size, loc, pBlock, pWls->nAllocBlocks);
170
171     //printf("[%p]\n", pBlock);
172
173     pWls->nTotalAllocCnt++;
174     if (loc < MAX_DL_BUF_LOCATIONS)
175         pWls->nTotalDlBufAllocCnt++;
176     else if (loc < MAX_UL_BUF_LOCATIONS)
177         pWls->nTotalUlBufAllocCnt++;
178
179     pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock_alloc);
180     return pBlock;
181 }
182
183 uint32_t wls_fapi_create_mem_array(PWLS_FAPI_MEM_STRUCT pMemArray, void *pMemArrayMemory, uint32_t totalSize, uint32_t nBlockSize)
184 {
185
186     int numBlocks = totalSize / nBlockSize;
187     void **ptr;
188     uint32_t i;
189
190     printf("wls_fapi_create_mem_array: pMemArray[%p] pMemArrayMemory[%p] totalSize[%d] nBlockSize[%d] numBlocks[%d]\n",
191         pMemArray, pMemArrayMemory, totalSize, nBlockSize, numBlocks);
192
193     // Can't be less than pointer size
194     if (nBlockSize < sizeof(void *))
195     {
196         return FAILURE;
197     }
198
199     // Can't be less than one block
200     if (totalSize < sizeof(void *))
201     {
202         return FAILURE;
203     }
204
205     pMemArray->ppFreeBlock = (void **)pMemArrayMemory;
206     pMemArray->pStorage = pMemArrayMemory;
207     pMemArray->pEndOfStorage = ((unsigned long*)pMemArrayMemory) + numBlocks * nBlockSize / sizeof(unsigned long);
208     pMemArray->nBlockSize = nBlockSize;
209     pMemArray->nBlockCount = numBlocks;
210
211     // Initialize single-linked list of free blocks;
212     ptr = (void **)pMemArrayMemory;
213     for (i = 0; i < pMemArray->nBlockCount; i++)
214     {
215 #ifdef MEMORY_CORRUPTION_DETECT
216         // Fill with some pattern
217         uint8_t *p = (uint8_t *)ptr;
218         uint32_t j;
219
220         p += (nBlockSize - 16);
221         for (j = 0; j < 16; j++)
222         {
223             p[j] = MEMORY_CORRUPTION_DETECT_FLAG;
224         }
225 #endif
226
227         if (i == pMemArray->nBlockCount - 1)
228         {
229             *ptr = NULL;      // End of list
230         }
231         else
232         {
233             // Points to the next block
234             *ptr = (void **)(((uint8_t*)ptr) + nBlockSize);
235             ptr += nBlockSize / sizeof(unsigned long);
236         }
237     }
238
239     memset(alloc_track, 0, sizeof(uint8_t) * ALLOC_TRACK_SIZE);
240
241     return SUCCESS;
242 }
243
244 uint32_t wls_fapi_alloc_mem_array(PWLS_FAPI_MEM_STRUCT pMemArray, void **ppBlock)
245 {
246     int idx;
247
248     if (pMemArray->ppFreeBlock == NULL)
249     {
250         printf("wls_fapi_alloc_mem_array pMemArray->ppFreeBlock = NULL\n");
251         return FAILURE;
252     }
253
254     // FIXME: Remove after debugging
255     if (((void *) pMemArray->ppFreeBlock < pMemArray->pStorage) ||
256         ((void *) pMemArray->ppFreeBlock >= pMemArray->pEndOfStorage))
257     {
258         printf("wls_fapi_alloc_mem_array ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
259                 pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock);
260         return FAILURE;
261     }
262
263     pMemArray->ppFreeBlock = (void **)((unsigned long)pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
264     *pMemArray->ppFreeBlock = (void **)((unsigned long)*pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
265
266     if ((*pMemArray->ppFreeBlock != NULL) &&
267         (((*pMemArray->ppFreeBlock) < pMemArray->pStorage) ||
268         ((*pMemArray->ppFreeBlock) >= pMemArray->pEndOfStorage)))
269     {
270         fprintf(stderr, "ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
271                 pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
272                 *pMemArray->ppFreeBlock);
273         return FAILURE;
274     }
275
276     *ppBlock = (void *) pMemArray->ppFreeBlock;
277     pMemArray->ppFreeBlock = (void **) (*pMemArray->ppFreeBlock);
278
279     idx = (((uint64_t)*ppBlock - (uint64_t)pMemArray->pStorage)) / pMemArray->nBlockSize;
280     if (alloc_track[idx])
281     {
282         printf("wls_fapi_alloc_mem_array Double alloc Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
283             pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
284             *pMemArray->ppFreeBlock);
285     }
286     else
287     {
288 #ifdef MEMORY_CORRUPTION_DETECT
289         uint32_t nBlockSize = pMemArray->nBlockSize, i;
290         uint8_t *p = (uint8_t *)*ppBlock;
291
292         p += (nBlockSize - 16);
293         for (i = 0; i < 16; i++)
294         {
295             p[i] = MEMORY_CORRUPTION_DETECT_FLAG;
296         }
297 #endif
298         alloc_track[idx] = 1;
299     }
300
301     //printf("Block allocd [%p,%p]\n", pMemArray, *ppBlock);
302
303     return SUCCESS;
304 }
305
306
307
308 uint8_t wls_fapi_create_partition(p_nr5g_fapi_wls_context_t pWls)
309 {
310 static long hugePageSize = WLS_HUGE_DEF_PAGE_SIZEA;
311      void *pPartitionMemBase;
312      uint32_t nPartitionMemSize;
313      uint32_t nTotalBlocks;
314      
315     pWls->pPartitionMemBase = pWls->pWlsMemBase + hugePageSize;
316     pWls->nPartitionMemSize = (pWls->nTotalMemorySize - hugePageSize);
317
318     pWls->nTotalBlocks = pWls->nPartitionMemSize / MSG_MAXSIZE1;
319
320     return wls_fapi_create_mem_array(&pWls->sWlsStruct, pWls->pPartitionMemBase, pWls->nPartitionMemSize, MSG_MAXSIZE1);
321 }
322
323 uint8_t nr5g_fapi2Phy_wls_init(p_nr5g_fapi_wls_context_t pWls)
324 {
325     int nBlocks = 0;
326     uint8_t retval = SUCCESS;
327
328
329     WLS_HANDLE h_wls =  pWls->h_wls[NR5G_FAPI2PHY_WLS_INST];
330     pthread_mutex_init((pthread_mutex_t *)&pWls->lock, NULL);
331     pthread_mutex_init((pthread_mutex_t *)&pWls->lock_alloc, NULL);
332
333     pWls->nTotalAllocCnt = 0;
334     pWls->nTotalFreeCnt = 0;
335     pWls->nTotalUlBufAllocCnt = 0;
336     pWls->nTotalUlBufFreeCnt = 0;
337     pWls->nTotalDlBufAllocCnt = 0;
338     pWls->nTotalDlBufFreeCnt = 0;
339     // Need to add wls_fapi_create_partition
340     retval = wls_fapi_create_partition(pWls);
341     if (retval == SUCCESS)
342     {   
343         gwls_fapi_ready = 1;
344         nBlocks = WLS_EnqueueBlock(h_wls, nr5g_fapi_wls_va_to_pa( h_wls, wls_fapi_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+2)));
345         printf("WLS_EnqueueBlock [%d]\n", nBlocks);
346         // Allocate Blocks for UL Transmission
347         while(WLS_EnqueueBlock(h_wls, nr5g_fapi_wls_va_to_pa(h_wls,wls_fapi_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+3))))
348         {
349          nBlocks++;
350         }
351         printf ("fapi2Phy UL Buffer Allocation completed\n");
352     }
353     else
354     {
355         printf ("can't create WLS FAPI2PHY partition \n");
356         return FAILURE;
357     }
358     return retval;
359 }
360
361 uint8_t nr5g_fapi_fapi2mac_wls_ready()
362 {
363     int ret = SUCCESS;
364     ret = WLS_Ready1(nr5g_fapi_fapi2mac_wls_instance());
365     return ret;
366 }
367
368
369 inline uint8_t nr5g_fapi_fapi2phy_wls_ready()
370 {
371     int ret = SUCCESS;
372     //NR5G_FAPI_LOG(TRACE_LOG, ("Waiting for L1 to respond in WLS Ready"));
373     ret = WLS_Ready(nr5g_fapi_fapi2phy_wls_instance());
374     return ret;
375 }
376
377 int main()
378 {
379     uint8_t ret;
380     uint64_t p_msg;
381     uint8_t retval= FAILURE;
382     p_nr5g_fapi_wls_context_t pwls;
383
384     // DPDK init
385     ret = fapi_dpdk_init();
386     if (ret)
387     {
388         printf("\n[FAPI] DPDK Init - Failed\n");
389         return FAILURE;
390     }
391     printf("\n[FAPI] DPDK Init - Done\n");
392
393     // WLS init
394     ret = fapi_wls_init(WLS_TEST_DEV_NAME, WLS_TEST_MEM_SIZE);
395     if(ret)
396     {
397         printf("\n[FAPI] WLS Init - Failed\n");
398         return FAILURE;
399     }
400     // Need to check for L1 and L2 started before attempting partition creation
401     // First let's wait for the L1 and L2 to be present
402     while (retval)
403     {
404         retval = nr5g_fapi_fapi2phy_wls_ready();
405     }
406     // Now the L2 is up so let's make sure that the L1 was started first
407     retval=FAILURE;
408     while (retval)
409     {
410         retval = nr5g_fapi_fapi2mac_wls_ready();
411     }
412     // Now that the L2 is up and has completed the Common Memory initialization the FT needs to initialize the FAPI2PHY buffers
413     pwls = nr5g_fapi_wls_context();
414     usleep(1000000);
415     ret = nr5g_fapi2Phy_wls_init(pwls);
416     if(ret)
417     {
418         printf("\n[FAPI] 2Phy WLS Init - Failed\n");
419         return FAILURE;
420     }
421     
422     printf("\n[FAPI] WLS Init - Done\n");
423
424     // Receive from MAC WLS
425     p_msg = fapi_mac_recv();
426     if (!p_msg)
427     {
428         printf("\n[FAPI] Receive from MAC - Failed\n");
429         return FAILURE;
430     }
431     printf("\n[FAPI] Receive from MAC - Done\n");
432
433     // Sent to PHY WLS
434     ret = fapi_phy_send();
435     if (ret)
436     {
437         printf("\n[FAPI] Send to PHY - Failed\n");
438         return FAILURE;
439     }
440     printf("\n[FAPI] Send to PHY - Done\n");
441
442     // Receive from PHY WLS
443     p_msg = fapi_phy_recv();
444     if (!p_msg)
445     {
446         printf("\n[FAPI] Receive from PHY - Failed\n");
447         return FAILURE;
448     }
449     printf("\n[FAPI] Receive from PHY - Done\n");
450
451     // Sent to MAC WLS
452     ret = fapi_mac_send();
453     if (ret)
454     {
455         printf("\n[FAPI] Send to MAC - Failed\n");
456         return FAILURE;
457     }
458     printf("\n[FAPI] Send to MAC - Done\n");
459
460
461     printf("\n[FAPI] Exiting...\n");
462
463     return SUCCESS;
464 }
465
466 uint8_t fapi_dpdk_init(void)
467 {
468     char whitelist[32];
469     uint8_t i;
470
471     char *argv[] = {"fapi_app", "--proc-type=secondary",
472         "--file-prefix", "wls", whitelist};
473     
474     int argc = RTE_DIM(argv);
475
476     /* initialize EAL first */
477     sprintf(whitelist, "-w %s",  "0000:00:06.0");
478     printf("[FAPI] Calling rte_eal_init: ");
479
480     for (i = 0; i < RTE_DIM(argv); i++)
481     {
482         printf("%s ", argv[i]);
483     }
484     printf("\n");
485
486     if (rte_eal_init(argc, argv) < 0)
487         rte_panic("Cannot init EAL\n");
488
489     return SUCCESS;
490 }
491
492 uint8_t fapi_wls_init(const char *dev_name, unsigned long long mem_size)
493 {
494     uint8_t *pMemZone;
495     static const struct rte_memzone *mng_memzone;
496     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();    
497     wls_drv_ctx_t *pDrv_ctx;
498
499     p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST] =
500      WLS_Open_Dual(dev_name, WLS_SLAVE_CLIENT, mem_size, &p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST]);
501     if((NULL == p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST]) && 
502             (NULL == p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST]))
503     {
504         return FAILURE;
505     }
506     g_shmem_size = mem_size;
507     p_wls_ctx->shmem_size = mem_size;
508     // Issue WLS_Alloc() for FAPI2MAC
509     p_wls_ctx->shmem = WLS_Alloc(
510             p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST],
511             p_wls_ctx->shmem_size);
512
513     if (NULL == p_wls_ctx->shmem)
514     {
515         printf("Unable to alloc WLS Memory for FAPI2MAC\n");
516         return FAILURE;
517     }            
518     p_wls_ctx->shmem = WLS_Alloc(
519             p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST],
520             p_wls_ctx->shmem_size);
521     p_wls_ctx->pWlsMemBase = p_wls_ctx->shmem;
522     p_wls_ctx->nTotalMemorySize = p_wls_ctx->shmem_size;
523     if (NULL == p_wls_ctx->shmem)
524     {
525         printf("Unable to alloc WLS Memory for FAPI2PHY\n");
526         return FAILURE;
527     }
528     
529     return SUCCESS;
530 }    
531     
532
533 uint64_t fapi_mac_recv()
534 {
535     uint8_t  num_blks = 0;
536     uint64_t p_msg;
537     uint32_t msg_size;
538     uint16_t msg_id;
539     uint16_t flags;
540     uint32_t i;
541  
542     WLS_HANDLE wls= nr5g_fapi_fapi2mac_wls_instance();
543     
544     for (i=0; i < NUM_TEST_MSGS; i++)
545     {
546     num_blks = WLS_Wait1(wls);
547     
548     if (num_blks)
549     {
550         p_msg = WLS_Get1(wls, &msg_size, &msg_id, &flags);
551     }
552     else
553     {
554         printf("\n[FAPI] FAPI2MAC WLS wait returned 0 blocks\n");
555     }
556                 if (p_msg)
557                 {
558                         printf("\n[FAPI] Receive from MAC Msg  %d-\n", i);
559           }
560     }             
561     return p_msg;
562 }
563
564 uint8_t fapi_phy_send()
565 {
566     uint64_t pa_block = 0;
567     uint8_t ret = FAILURE;
568     uint32_t i;
569     WLS_HANDLE wls = nr5g_fapi_fapi2mac_wls_instance();
570     WLS_HANDLE wlsp = nr5g_fapi_fapi2phy_wls_instance();
571     
572     for (i=0; i < NUM_TEST_MSGS; i++)
573     {
574     pa_block = (uint64_t) WLS_DequeueBlock((void*) wls);
575     if (!pa_block)
576     {
577         printf("\n[FAPI] FAPI2MAC WLS Dequeue block error %d\n",i);
578         return FAILURE;
579     }
580
581         ret = WLS_Put(wlsp, pa_block, WLS_TEST_MSG_SIZE, WLS_TEST_MSG_ID, (i== (NUM_TEST_MSGS-1))? WLS_TF_FIN:0);
582       if (ret)
583         {
584         printf("\n[FAPI] Send to PHY %d- Failed\n",i);
585         return FAILURE;
586         }
587         else
588         {
589                 printf("\n[FAPI] Send to PHY %d done \n",i);
590         }
591     }
592     return ret;
593 }
594
595 uint64_t fapi_phy_recv()
596 {
597     uint8_t  num_blks = 0;
598     uint64_t p_msg;
599     uint32_t msg_size;
600     uint16_t msg_id;
601     uint16_t flags;
602     uint32_t i=0;
603     WLS_HANDLE wls = nr5g_fapi_fapi2phy_wls_instance();
604     
605     while (1)
606     {
607     num_blks = WLS_Wait(wls);
608     printf("WLS_Wait returns %d\n",num_blks);
609     
610     if (num_blks)
611     {
612         p_msg = WLS_Get(wls, &msg_size, &msg_id, &flags);
613         printf("\n[FAPI] FAPI2PHY Received Block %d \n", i);
614         i++;
615         if (flags & WLS_TF_FIN)
616         {
617                 return p_msg;
618         }
619     }
620     else
621     {
622         printf("\n[FAPI] FAPI2MAC WLS wait returned 0 blocks\n");
623     }
624     }
625     return p_msg;
626 }
627
628 uint8_t fapi_mac_send()
629 {
630     uint64_t pa_block = 0;
631     uint8_t ret = FAILURE;
632     uint32_t i;
633     WLS_HANDLE wls = nr5g_fapi_fapi2mac_wls_instance();
634     WLS_HANDLE wlsp = nr5g_fapi_fapi2phy_wls_instance();
635     
636     for (i=0; i < NUM_TEST_MSGS; i++)
637     {
638     pa_block = (uint64_t) WLS_DequeueBlock((void*) wlsp);
639     if (!pa_block)
640     {
641         printf("\n[FAPI] FAPI2MAC WLS Dequeue block %d error\n",i);
642         return FAILURE;
643     }
644
645         ret = WLS_Put1(wls, pa_block, WLS_TEST_MSG_SIZE, WLS_TEST_MSG_ID, (i== (NUM_TEST_MSGS-1))? WLS_TF_FIN:0);
646         printf("\n[FAPI] FAPI2MAC WLS Put1 block %d\n",i);
647     }
648     return ret;
649 }