* INTC Contribution to the O-RAN F Release for O-DU Low
[o-du/phy.git] / fapi_5g / source / framework / wls / lib / nr5g_fapi_wls.c
1 /******************************************************************************
2 *
3 *   Copyright (c) 2021 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  * @file This file has Shared Memory interface functions between FAPI and PHY
21  * @defgroup nr5g_fapi_source_framework_wls_lib_group
22  **/
23
24 #include "nr5g_fapi_framework.h"
25 #include "nr5g_fapi_internal.h"
26 #include "nr5g_fapi_wls.h"
27 #include "nr5g_fapi_config_loader.h"
28 #include "nr5g_fapi_log.h"
29 #include "nr5g_fapi_memory.h"
30
31 #define WLS_HUGE_DEF_PAGE_SIZEA 0x40000000LL
32
33 nr5g_fapi_wls_context_t g_wls_ctx;
34
35 static uint8_t alloc_track[ALLOC_TRACK_SIZE];
36
37 //------------------------------------------------------------------------------
38 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
39  *
40  *  @param void
41  *
42  *  @return  A pointer to WLS Context stucture
43  *
44  *  @description
45  *  This function returns the WLS Context structure which has WLS related parameters
46  *
47 **/
48 //------------------------------------------------------------------------------
49 inline p_nr5g_fapi_wls_context_t nr5g_fapi_wls_context(
50     )
51 {
52     return &g_wls_ctx;
53 }
54
55 //----------------------------------------------------------------------------------
56 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
57  *
58  *  @param void
59  *
60  *  @return  0 if SUCCESS
61  *
62  *  @description
63  *  This function is called at WLS init and waits in an infinite for L1 to respond back with some information
64  *  needed by the L2
65  *
66 **/
67 //----------------------------------------------------------------------------------
68 inline uint8_t nr5g_fapi_fapi2phy_wls_ready(
69     )
70 {
71     int retval = 0;
72     p_nr5g_fapi_wls_context_t p_wls = nr5g_fapi_wls_context();
73
74     retval = WLS_Ready(p_wls->h_wls[NR5G_FAPI2PHY_WLS_INST]);
75
76     return retval;
77 }
78
79 //------------------------------------------------------------------------------
80 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
81  *
82  *  @param[in]   ptr Pointer to display
83  *  @param[in]   size Size of data
84  *
85  *  @return  void
86  *
87  *  @description
88  *  This function displays content of Buffer - Used for debugging
89  *
90 **/
91 //------------------------------------------------------------------------------
92 void nr5g_fapi_wls_show_data(
93     void *ptr,
94     uint32_t size)
95 {
96     uint8_t *d = ptr;
97     uint32_t i;
98
99     for (i = 0; i < size; i++) {
100         if (!(i & 0xf))
101             printf("\n");
102         printf("%02x ", d[i]);
103     }
104     printf("\n");
105 }
106
107 //------------------------------------------------------------------------------
108 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
109  *
110  *  @param   N/A
111  *
112  *  @return  N/A
113  *
114  *  @description
115  *  This function prints to the console FAPI stats
116  *
117 **/
118 //------------------------------------------------------------------------------
119 void nr5g_fapi_wls_print_stats(
120     void)
121 {
122     p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
123     printf("          nTotalBlocks[%5d]  nAllocBlocks[%5d]  nFreeBlocks[%5d]\n",
124         pWls->nTotalBlocks, pWls->nAllocBlocks,
125         (pWls->nTotalBlocks - pWls->nAllocBlocks));
126     printf("        nTotalAllocCnt[%5d] nTotalFreeCnt[%5d]         Diff[%5d]\n",
127         pWls->nTotalAllocCnt, pWls->nTotalFreeCnt,
128         (pWls->nTotalAllocCnt - pWls->nTotalFreeCnt));
129     uint32_t nFinalTotalDlBufAllocCnt = 0, nFinalTotalDlBufFreeCnt = 0, idx;
130
131 //#define PRINTF_DEBUG(fmt, args...) //printf(fmt, ## args)
132 #define PRINTF_DEBUG(fmt, args...)
133     PRINTF_DEBUG("\n");
134     PRINTF_DEBUG("\n        nDlBufAllocCnt: \n");
135     for (idx = 0; idx < MEM_STAT_DEFAULT; idx++) {
136         nFinalTotalDlBufAllocCnt += pWls->nTotalDlBufAllocCnt[idx];
137         PRINTF_DEBUG("[%3d:%5d] ", idx, pWls->nTotalDlBufAllocCnt[idx]);
138     }
139     PRINTF_DEBUG("\n");
140     PRINTF_DEBUG("\n         nDlBufFreeCnt: \n");
141     for (idx = 0; idx < MEM_STAT_DEFAULT; idx++) {
142         nFinalTotalDlBufFreeCnt += pWls->nTotalDlBufFreeCnt[idx];
143         PRINTF_DEBUG("[%3d:%5d] ", idx, pWls->nTotalDlBufFreeCnt[idx]);
144     }
145     PRINTF_DEBUG("\n\n");
146
147     printf("        nDlBufAllocCnt[%5d] nDlBufFreeCnt[%5d]         Diff[%5d]\n",
148         nFinalTotalDlBufAllocCnt, nFinalTotalDlBufFreeCnt,
149         (nFinalTotalDlBufAllocCnt - nFinalTotalDlBufFreeCnt));
150     printf
151         ("        nUlBufAllocCnt[%5d] nUlBufFreeCnt[%5d]         Diff[%5d]\n\n",
152         pWls->nTotalUlBufAllocCnt, pWls->nTotalUlBufFreeCnt,
153         (pWls->nTotalUlBufAllocCnt - pWls->nTotalUlBufFreeCnt));
154 }
155
156 //------------------------------------------------------------------------------
157 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
158  *
159  *  @param[in]   ptr Address to convert
160  *
161  *  @return  Converted address
162  *
163  *  @description
164  *  This function converts Virtual Address to Physical Address
165  *
166 **/
167 //------------------------------------------------------------------------------
168 uint64_t nr5g_fapi_wls_va_to_pa(
169     WLS_HANDLE h_wls,
170     void *ptr)
171 {
172     return ((uint64_t) WLS_VA2PA(h_wls, ptr));
173 }
174
175 //------------------------------------------------------------------------------
176 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
177  *
178  *  @param[in]   ptr Address to convert
179  *
180  *  @return  Converted address
181  *
182  *  @description
183  *  This function converts Physical Address to Virtual Address
184  *
185 **/
186 //------------------------------------------------------------------------------
187 void *nr5g_fapi_wls_pa_to_va(
188     WLS_HANDLE h_wls,
189     uint64_t ptr)
190 {
191     return ((void *)WLS_PA2VA(h_wls, ptr));
192 }
193
194 //------------------------------------------------------------------------------
195 /** @ingroup nr5g_fapi_source_framework_wls_lib_group 
196  *
197  *  @param   void
198  *
199  *  @return  Number of blocks added
200  *
201  *  @description
202  *  This function add WLS blocks to the L1 Array which will be used by L1 in 
203  *  every TTI to populate and send back APIs to the MAC
204  *
205 **/
206 //------------------------------------------------------------------------------
207 uint32_t wls_fapi_add_blocks_to_ul(
208     void)
209 {
210     uint32_t num_blocks = 0;
211     p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
212     WLS_HANDLE h_wls = pWls->h_wls[NR5G_FAPI2PHY_WLS_INST];
213
214     void *pMsg = wls_fapi_alloc_buffer(0, MIN_UL_BUF_LOCATIONS);
215     if (!pMsg) {
216         return num_blocks;
217     }
218
219     /* allocate blocks for UL transmittion */
220     while (WLS_EnqueueBlock(h_wls, nr5g_fapi_wls_va_to_pa(h_wls, pMsg)) > 0) {
221         num_blocks++;
222         pMsg = wls_fapi_alloc_buffer(0, MIN_UL_BUF_LOCATIONS);
223         if (!pMsg)
224             break;
225     }
226
227     // free not enqueued block
228     if (pMsg) {
229         wls_fapi_free_buffer(pMsg, MIN_UL_BUF_LOCATIONS);
230     }
231
232     return num_blocks;
233 }
234
235 //------------------------------------------------------------------------------
236 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
237  *
238  *  @param          A pointer to the phy instance table.
239  *
240  *  @return         0 if SUCCESS
241  *
242  *  @description    This function initializes WLS layer primitives and allocates
243  *                  memory needed to exchange APIs between FAPI and PHY.
244 **/
245 //------------------------------------------------------------------------------
246 uint8_t nr5g_fapi_wls_init(
247     p_nr5g_fapi_cfg_t cfg)
248 {
249     uint64_t mac_shmem_size = 0;
250     uint64_t phy_shmem_size = 0;
251
252     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
253
254     if (p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST] &&
255         p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST]) {
256         // NR5G_FAPI_LOG(ERROR_LOG, ("WLS instance already opened!"));
257         return FAILURE;
258     }
259
260     p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST] =
261         WLS_Open_Dual(basename(cfg->wls.device_name), WLS_SLAVE_CLIENT,
262         &mac_shmem_size, &phy_shmem_size, &p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST]);
263     
264     cfg->wls.shmem_size = mac_shmem_size + phy_shmem_size;
265     p_wls_ctx->shmem_size = cfg->wls.shmem_size;
266     if ((NULL == p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST]) &&
267         (NULL == p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST])) {
268         NR5G_FAPI_LOG(ERROR_LOG, ("[NR5G_FAPI_ WLS] WLS Open Dual Failed."));
269         return FAILURE;
270     }
271     // Issue WLS_Alloc() for FAPI2MAC
272     p_wls_ctx->shmem = WLS_Alloc(p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST],
273         p_wls_ctx->shmem_size);
274
275     if (NULL == p_wls_ctx->shmem) {
276         printf("Unable to alloc WLS Memory for FAPI2MAC\n");
277         return FAILURE;
278     }
279
280     p_wls_ctx->shmem = WLS_Alloc(p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST],
281         p_wls_ctx->shmem_size);
282     p_wls_ctx->pWlsMemBase = p_wls_ctx->shmem;
283     p_wls_ctx->nTotalMemorySize = mac_shmem_size;
284     if (NULL == p_wls_ctx->shmem) {
285         printf("Unable to alloc WLS Memory\n");
286         return FAILURE;
287     }
288     // Now the L2 is up so let's make sure that the L1 was started first
289     usleep(1000000);
290     // First let's wait for the L1 and L2 to be present
291     while (nr5g_fapi_fapi2phy_wls_ready()) ;
292     NR5G_FAPI_LOG(INFO_LOG, ("L1 is up..."));
293     // Now the L2 is up so let's make sure that the L1 was started first
294     while (nr5g_fapi_fapi2mac_wls_ready()) ;
295     NR5G_FAPI_LOG(INFO_LOG, ("L2 is up..."));
296
297     // Now that the L2 is up and has completed the Common Memory initialization
298     usleep(1000000);
299     if (FAILURE == nr5g_fapi_wls_memory_init()) {
300         return FAILURE;
301     }
302
303     pthread_mutex_init((pthread_mutex_t *)
304         & p_wls_ctx->fapi2phy_lock_send, NULL);
305     pthread_mutex_init((pthread_mutex_t *)
306         & p_wls_ctx->fapi2phy_lock_alloc, NULL);
307     pthread_mutex_init((pthread_mutex_t *)
308         & p_wls_ctx->fapi2mac_lock_send, NULL);
309     pthread_mutex_init((pthread_mutex_t *)
310         & p_wls_ctx->fapi2mac_lock_alloc, NULL);
311     return SUCCESS;
312 }
313
314 //-------------------------------------------------------------------------------------------
315 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
316  *
317  *  @param[in]   pMemArray Pointer to WLS Memory Management Structure
318  *  @param[in]   pMemArrayMmeory pointer to flat buffer that was allocated
319  *  @param[in]   totalSize total size of flat buffer allocated
320  *  @param[in]   nBlockSize Size of each block that needs to be partitoned by the memory manager
321  *
322  *  @return  0 if SUCCESS
323  *
324  *  @description
325  *  This function creates memory blocks from a flat buffer which will be used for communication between FAPI and PHY
326  *
327 **/
328 //-------------------------------------------------------------------------------------------
329 uint32_t wls_fapi_create_mem_array(
330     PWLS_FAPI_MEM_STRUCT pMemArray,
331     void *pMemArrayMemory,
332     uint32_t totalSize,
333     uint32_t nBlockSize)
334 {
335
336     int numBlocks = totalSize / nBlockSize;
337     void **ptr;
338     uint32_t i;
339
340     printf
341         ("wls_fapi_create_mem_array: pMemArray[%p] pMemArrayMemory[%p] totalSize[%d] nBlockSize[%d] numBlocks[%d]\n",
342         pMemArray, pMemArrayMemory, totalSize, nBlockSize, numBlocks);
343
344     // Can't be less than pointer size
345     if (nBlockSize < sizeof(void *)) {
346         return FAILURE;
347     }
348     // Can't be less than one block
349     if (totalSize < sizeof(void *)) {
350         return FAILURE;
351     }
352
353     pMemArray->ppFreeBlock = (void **)pMemArrayMemory;
354     pMemArray->pStorage = pMemArrayMemory;
355     pMemArray->pEndOfStorage =
356         ((unsigned long *)pMemArrayMemory) +
357         numBlocks * nBlockSize / sizeof(unsigned long);
358     pMemArray->nBlockSize = nBlockSize;
359     pMemArray->nBlockCount = numBlocks;
360
361     // Initialize single-linked list of free blocks;
362     ptr = (void **)pMemArrayMemory;
363     for (i = 0; i < pMemArray->nBlockCount; i++) {
364 #ifdef MEMORY_CORRUPTION_DETECT
365         // Fill with some pattern
366         uint8_t *p = (uint8_t *) ptr;
367         uint32_t j;
368
369         p += (nBlockSize - 16);
370         for (j = 0; j < 16; j++) {
371             p[j] = MEMORY_CORRUPTION_DETECT_FLAG;
372         }
373 #endif
374
375         if (i == pMemArray->nBlockCount - 1) {
376             *ptr = NULL;        // End of list
377         } else {
378             // Points to the next block
379             *ptr = (void **)(((uint8_t *) ptr) + nBlockSize);
380             ptr += nBlockSize / sizeof(unsigned long);
381         }
382     }
383
384     NR5G_FAPI_MEMSET(alloc_track, sizeof(uint8_t) * ALLOC_TRACK_SIZE, 0,
385         sizeof(uint8_t) * ALLOC_TRACK_SIZE);
386
387     return SUCCESS;
388 }
389
390 //-------------------------------------------------------------------------------------------
391 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
392  *
393  *  @param[in]   pWls Pointer to the nr5g_fapi_wls_ctx structure
394  *
395  *  @return  0 if SUCCESS
396  *
397  *  @description
398  *  This function created a partition and blocks of WLS memory for API exchange between FAPI and PHY
399  *
400 **/
401 //-------------------------------------------------------------------------------------------
402 uint8_t wls_fapi_create_partition(
403     p_nr5g_fapi_wls_context_t pWls)
404 {
405     uint64_t nWlsMemBaseUsable;
406     uint64_t nTotalMemorySizeUsable;
407     uint64_t nBalance, nBlockSize, nBlockSizeMask, nHugepageSizeMask;
408
409     nBlockSize = MSG_MAXSIZE;
410     nWlsMemBaseUsable = (uint64_t)pWls->pWlsMemBase;
411     nTotalMemorySizeUsable = pWls->nTotalMemorySize - WLS_HUGE_DEF_PAGE_SIZEA;
412     nBlockSizeMask = nBlockSize-1;
413
414     // Align Starting Location
415     nWlsMemBaseUsable = (nWlsMemBaseUsable + nBlockSizeMask) & (~nBlockSizeMask);
416     nBalance = nWlsMemBaseUsable - (uint64_t)pWls->pWlsMemBase;
417     nTotalMemorySizeUsable -= nBalance;
418
419     // Align Ending Location
420     nBalance = nTotalMemorySizeUsable % nBlockSize;
421     nTotalMemorySizeUsable -= nBalance;
422
423     // Move start location to the next hugepage boundary
424     nHugepageSizeMask = WLS_HUGE_DEF_PAGE_SIZEA-1;
425     nWlsMemBaseUsable = (nWlsMemBaseUsable + WLS_HUGE_DEF_PAGE_SIZEA) & (~nHugepageSizeMask);
426
427
428     pWls->pPartitionMemBase = (void *)nWlsMemBaseUsable;
429     pWls->nPartitionMemSize = nTotalMemorySizeUsable;
430     pWls->nTotalBlocks = pWls->nPartitionMemSize / nBlockSize;
431     return wls_fapi_create_mem_array(&pWls->sWlsStruct, pWls->pPartitionMemBase,
432         pWls->nPartitionMemSize, nBlockSize);
433 }
434
435 //------------------------------------------------------------------------------
436 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
437  *
438  *  @param[in]      A pointer to the FAPI Memory Structure (Initialized by L2)
439  *  @param[out]     ppBlock Pointer where the allocated memory block is stored     
440  *
441  *  @return         0 if SUCCESS
442  *
443  *  @description    This function allocates a memory block from the pool
444  *
445 **/
446 //------------------------------------------------------------------------------
447 uint32_t wls_fapi_alloc_mem_array(
448     PWLS_FAPI_MEM_STRUCT pMemArray,
449     void **ppBlock)
450 {
451     int idx;
452
453     if (pMemArray->ppFreeBlock == NULL) {
454         printf("wls_fapi_alloc_mem_array pMemArray->ppFreeBlock = NULL\n");
455         return FAILURE;
456     }
457     // FIXME: Remove after debugging
458     if (((void *)pMemArray->ppFreeBlock < pMemArray->pStorage) ||
459         ((void *)pMemArray->ppFreeBlock >= pMemArray->pEndOfStorage)) {
460         printf
461             ("wls_fapi_alloc_mem_array ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
462             pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock);
463         return FAILURE;
464     }
465
466     pMemArray->ppFreeBlock =
467         (void **)((unsigned long)pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
468     *pMemArray->ppFreeBlock =
469         (void **)((unsigned long)*pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
470
471     if ((*pMemArray->ppFreeBlock != NULL) &&
472         (((*pMemArray->ppFreeBlock) < pMemArray->pStorage) ||
473             ((*pMemArray->ppFreeBlock) >= pMemArray->pEndOfStorage))) {
474         fprintf(stderr,
475             "ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
476             pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
477             *pMemArray->ppFreeBlock);
478         return FAILURE;
479     }
480
481     *ppBlock = (void *)pMemArray->ppFreeBlock;
482     pMemArray->ppFreeBlock = (void **)(*pMemArray->ppFreeBlock);
483
484     idx =
485         (((uint64_t) * ppBlock -
486             (uint64_t) pMemArray->pStorage)) / pMemArray->nBlockSize;
487     if (alloc_track[idx]) {
488         printf
489             ("wls_fapi_alloc_mem_array Double alloc Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
490             pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
491             *pMemArray->ppFreeBlock);
492         return FAILURE;
493     } else {
494 #ifdef MEMORY_CORRUPTION_DETECT
495         uint32_t nBlockSize = pMemArray->nBlockSize, i;
496         uint8_t *p = (uint8_t *) * ppBlock;
497
498         p += (nBlockSize - 16);
499         for (i = 0; i < 16; i++) {
500             p[i] = MEMORY_CORRUPTION_DETECT_FLAG;
501         }
502 #endif
503         alloc_track[idx] = 1;
504     }
505
506     //printf("Block allocd [%p,%p]\n", pMemArray, *ppBlock);
507
508     return SUCCESS;
509 }
510
511 //------------------------------------------------------------------------------
512 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
513  *
514  *  @param[in]      A pointer to the FAPI Memory Structure (Initialized by L2)
515  *  @param[in]      pBlock Pointer where the allocated memory block is stored     
516  *
517  *  @return         0 if SUCCESS
518  *
519  *  @description    This function frees a WLS block of memory and adds 
520  *                  it back to the pool
521  *
522 **/
523 //------------------------------------------------------------------------------
524 uint32_t wls_fapi_free_mem_array(
525     PWLS_FAPI_MEM_STRUCT pMemArray,
526     void *pBlock)
527 {
528     int idx;
529     unsigned long mask = (((unsigned long)pMemArray->nBlockSize) - 1);
530
531     pBlock = (void *)((unsigned long)pBlock & ~mask);
532
533     if ((pBlock < pMemArray->pStorage) || (pBlock >= pMemArray->pEndOfStorage)) {
534         printf
535             ("wls_fapi_free_mem_array WARNING: Trying to free foreign block;Arr=%p,Blk=%p pStorage [%p .. %p]\n",
536             pMemArray, pBlock, pMemArray->pStorage, pMemArray->pEndOfStorage);
537         return FAILURE;
538     }
539
540     idx =
541         (int)(((uint64_t) pBlock -
542             (uint64_t) pMemArray->pStorage)) / pMemArray->nBlockSize;
543
544     if (alloc_track[idx] == 0) {
545         printf
546             ("wls_fapi_free_mem_array ERROR: Double free Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
547             pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock, pBlock);
548         return SUCCESS;
549     } else {
550 #ifdef MEMORY_CORRUPTION_DETECT
551         uint32_t nBlockSize = pMemArray->nBlockSize, i;
552         uint8_t *p = (uint8_t *) pBlock;
553
554         p += (nBlockSize - 16);
555         for (i = 0; i < 16; i++) {
556             if (p[i] != MEMORY_CORRUPTION_DETECT_FLAG) {
557                 printf("ERROR: Corruption\n");
558                 nr5g_fapi_wls_print_stats();
559                 exit(-1);
560             }
561         }
562 #endif
563         alloc_track[idx] = 0;
564     }
565
566     if (((void *)pMemArray->ppFreeBlock) == pBlock) {
567         // Simple protection against freeing of already freed block
568         return SUCCESS;
569     }
570     // FIXME: Remove after debugging
571     if ((pMemArray->ppFreeBlock != NULL)
572         && (((void *)pMemArray->ppFreeBlock < pMemArray->pStorage)
573             || ((void *)pMemArray->ppFreeBlock >= pMemArray->pEndOfStorage))) {
574         printf
575             ("wls_fapi_free_mem_array ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
576             pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock);
577         return FAILURE;
578     }
579     // FIXME: Remove after debugging
580     if ((pBlock < pMemArray->pStorage) || (pBlock >= pMemArray->pEndOfStorage)) {
581         printf("wls_fapi_free_mem_array ERROR: Invalid block;Arr=%p,Blk=%p\n",
582             pMemArray, pBlock);
583         return FAILURE;
584     }
585
586     *((void **)pBlock) =
587         (void **)((unsigned long)pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
588     pMemArray->ppFreeBlock =
589         (void **)((unsigned long)pBlock & 0xFFFFFFFFFFFFFFF0);
590
591     //printf("Block freed [%p,%p]\n", pMemArray, pBlock);
592
593     return SUCCESS;
594 }
595
596 //------------------------------------------------------------------------------
597 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
598  *
599  *  @param          size (if 0 fixed size from pool)
600  *  @param          Number of locations
601  *
602  *  @return         0 if SUCCESS
603  *
604  *  @description    This function initializes WLS layer primitives and allocates
605  *                  memory needed to exchange APIs between FAPI and PHY.
606 **/
607 //------------------------------------------------------------------------------
608 void *wls_fapi_alloc_buffer(
609     uint32_t size,
610     uint32_t loc)
611 {
612     void *pBlock = NULL;
613     p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
614
615     if (pthread_mutex_lock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
616         NR5G_FAPI_LOG(ERROR_LOG, ("unable to get lock alloc pthread mutex"));
617         exit(-1);
618     }
619
620     if (wls_fapi_alloc_mem_array(&pWls->sWlsStruct, &pBlock) != SUCCESS) {
621         printf("wls_fapi_alloc_buffer alloc error size[%d] loc[%d]\n", size,
622             loc);
623         nr5g_fapi_wls_print_stats();
624         exit(-1);
625     } else {
626         pWls->nAllocBlocks++;
627     }
628
629     //printf("----------------wls_fapi_alloc_buffer: size[%d] loc[%d] buf[%p] nAllocBlocks[%d]\n", size, loc, pBlock, pWls->nAllocBlocks);
630
631     //printf("[%p]\n", pBlock);
632
633     pWls->nTotalAllocCnt++;
634     if (loc < MAX_DL_BUF_LOCATIONS)
635         pWls->nTotalDlBufAllocCnt[loc]++;
636     else if (loc < MAX_UL_BUF_LOCATIONS)
637         pWls->nTotalUlBufAllocCnt++;
638
639     if (pthread_mutex_unlock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
640         NR5G_FAPI_LOG(ERROR_LOG, ("unable to unlock alloc pthread mutex"));
641         exit(-1);
642     }
643
644     return pBlock;
645 }
646
647 //------------------------------------------------------------------------------
648 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
649  *
650  *  @param[in]      *pMsg Pointer to free
651  *
652  *  @return         void
653  *
654  *  @descriptioni   This function frees a block of memory and adds it back to 
655  *                  the pool.
656  *
657 **/
658 //------------------------------------------------------------------------------
659 void wls_fapi_free_buffer(
660     void *pMsg,
661     uint32_t loc)
662 {
663     p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
664
665     if (pthread_mutex_lock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
666         NR5G_FAPI_LOG(ERROR_LOG, ("unable to lock alloc pthread mutex"));
667         exit(-1);
668     }
669     //printf("----------------wls_fapi_free_buffer: buf[%p] loc[%d]\n", pMsg, loc);
670     if (wls_fapi_free_mem_array(&pWls->sWlsStruct, (void *)pMsg) == SUCCESS) {
671         pWls->nAllocBlocks--;
672     } else {
673         printf("wls_fapi_free_buffer Free error\n");
674         nr5g_fapi_wls_print_stats();
675         exit(-1);
676     }
677
678     pWls->nTotalFreeCnt++;
679     if (loc < MAX_DL_BUF_LOCATIONS)
680         pWls->nTotalDlBufFreeCnt[loc]++;
681     else if (loc < MAX_UL_BUF_LOCATIONS)
682         pWls->nTotalUlBufFreeCnt++;
683
684     if (pthread_mutex_unlock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
685         NR5G_FAPI_LOG(ERROR_LOG, ("unable to unlock alloc pthread mutex"));
686         exit(-1);
687     }
688 }
689
690 //------------------------------------------------------------------------------
691 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
692  *
693  *  @param          A pointer to a wls instance
694  *
695  *  @return         0 if SUCCESS
696  *
697  *  @description    This function initializes the WLS layer FAPI2PHY interface 
698  *                  primitives and allocates memory needed to exchange APIs 
699  *                  between FAPI and PHY.
700 **/
701 //------------------------------------------------------------------------------
702 uint8_t nr5g_fapi_wls_memory_init(
703     )
704 {
705     uint32_t nBlocks = 0;
706     p_nr5g_fapi_wls_context_t p_wls = nr5g_fapi_wls_context();
707
708     if (FAILURE == wls_fapi_create_partition(p_wls))
709         return FAILURE;
710
711     if ((nBlocks = wls_fapi_add_blocks_to_ul()) == 0) {
712         NR5G_FAPI_LOG(ERROR_LOG, ("Unable to allocate blocks to PHY"));
713         return FAILURE;
714     }
715
716     return SUCCESS;
717 }