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