2ae97b067688d3b43993604e0ef7728170af4d6c
[o-du/phy.git] / fapi_5g / source / framework / wls / lib / nr5g_fapi_wls.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  * @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 nr5g_fapi_wls_context_t g_wls_ctx;
32
33 static uint32_t g_to_free_send_list_cnt[TO_FREE_SIZE] = { 0 };
34 static uint64_t g_to_free_send_list[TO_FREE_SIZE][TOTAL_FREE_BLOCKS] = { {0L} };
35 static uint32_t g_to_free_recv_list_cnt[TO_FREE_SIZE] = { 0 };
36 static uint64_t g_to_free_recv_list[TO_FREE_SIZE][TOTAL_FREE_BLOCKS] = { {0L} };
37
38 static uint8_t alloc_track[ALLOC_TRACK_SIZE];
39
40 //------------------------------------------------------------------------------
41 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
42  *
43  *  @param void
44  *
45  *  @return  A pointer to WLS Context stucture
46  *
47  *  @description
48  *  This function returns the WLS Context structure which has WLS related parameters
49  *
50 **/
51 //------------------------------------------------------------------------------
52 inline p_nr5g_fapi_wls_context_t nr5g_fapi_wls_context(
53     )
54 {
55     return &g_wls_ctx;
56 }
57
58 //------------------------------------------------------------------------------
59 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
60  *
61  *  @param[in]   ptr Pointer to display
62  *  @param[in]   size Size of data
63  *
64  *  @return  void
65  *
66  *  @description
67  *  This function displays content of Buffer - Used for debugging
68  *
69 **/
70 //------------------------------------------------------------------------------
71 void nr5g_fapi_wls_show_data(
72     void *ptr,
73     uint32_t size)
74 {
75     uint8_t *d = ptr;
76     int i;
77
78     for (i = 0; i < size; i++) {
79         if (!(i & 0xf))
80             printf("\n");
81         printf("%02x ", d[i]);
82     }
83     printf("\n");
84 }
85
86 //------------------------------------------------------------------------------
87 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
88  *
89  *  @param   N/A
90  *
91  *  @return  N/A
92  *
93  *  @description
94  *  This function prints to the console FAPI stats
95  *
96 **/
97 //------------------------------------------------------------------------------
98 void nr5g_fapi_wls_print_stats(
99     void)
100 {
101     p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
102     printf("          nTotalBlocks[%5d]  nAllocBlocks[%5d]  nFreeBlocks[%5d]\n",
103         pWls->nTotalBlocks, pWls->nAllocBlocks,
104         (pWls->nTotalBlocks - pWls->nAllocBlocks));
105     printf("        nTotalAllocCnt[%5d] nTotalFreeCnt[%5d]         Diff[%5d]\n",
106         pWls->nTotalAllocCnt, pWls->nTotalFreeCnt,
107         (pWls->nTotalAllocCnt - pWls->nTotalFreeCnt));
108     uint32_t nFinalTotalDlBufAllocCnt = 0, nFinalTotalDlBufFreeCnt = 0, idx;
109
110 //#define PRINTF_DEBUG(fmt, args...) //printf(fmt, ## args)
111 #define PRINTF_DEBUG(fmt, args...)
112     PRINTF_DEBUG("\n");
113     PRINTF_DEBUG("\n        nDlBufAllocCnt: \n");
114     for (idx = 0; idx < MEM_STAT_DEFAULT; idx++) {
115         nFinalTotalDlBufAllocCnt += pWls->nTotalDlBufAllocCnt[idx];
116         PRINTF_DEBUG("[%3d:%5d] ", idx, pWls->nTotalDlBufAllocCnt[idx]);
117     }
118     PRINTF_DEBUG("\n");
119     PRINTF_DEBUG("\n         nDlBufFreeCnt: \n");
120     for (idx = 0; idx < MEM_STAT_DEFAULT; idx++) {
121         nFinalTotalDlBufFreeCnt += pWls->nTotalDlBufFreeCnt[idx];
122         PRINTF_DEBUG("[%3d:%5d] ", idx, pWls->nTotalDlBufFreeCnt[idx]);
123     }
124     PRINTF_DEBUG("\n\n");
125
126     printf("        nDlBufAllocCnt[%5d] nDlBufFreeCnt[%5d]         Diff[%5d]\n",
127         nFinalTotalDlBufAllocCnt, nFinalTotalDlBufFreeCnt,
128         (nFinalTotalDlBufAllocCnt - nFinalTotalDlBufFreeCnt));
129     printf
130         ("        nUlBufAllocCnt[%5d] nUlBufFreeCnt[%5d]         Diff[%5d]\n\n",
131         pWls->nTotalUlBufAllocCnt, pWls->nTotalUlBufFreeCnt,
132         (pWls->nTotalUlBufAllocCnt - pWls->nTotalUlBufFreeCnt));
133 }
134
135 //------------------------------------------------------------------------------
136 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
137  *
138  *  @param[in]   ptr Address to convert
139  *
140  *  @return  Converted address
141  *
142  *  @description
143  *  This function converts Virtual Address to Physical Address
144  *
145 **/
146 //------------------------------------------------------------------------------
147 uint64_t nr5g_fapi_wls_va_to_pa(
148     WLS_HANDLE h_wls,
149     void *ptr)
150 {
151     return ((uint64_t) WLS_VA2PA(h_wls, ptr));
152 }
153
154 //------------------------------------------------------------------------------
155 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
156  *
157  *  @param[in]   ptr Address to convert
158  *
159  *  @return  Converted address
160  *
161  *  @description
162  *  This function converts Physical Address to Virtual Address
163  *
164 **/
165 //------------------------------------------------------------------------------
166 void *nr5g_fapi_wls_pa_to_va(
167     WLS_HANDLE h_wls,
168     uint64_t ptr)
169 {
170     return ((void *)WLS_PA2VA(h_wls, ptr));
171 }
172
173 //------------------------------------------------------------------------------
174 /** @ingroup nr5g_fapi_source_framework_wls_lib_group 
175  *
176  *  @param   void
177  *
178  *  @return  Number of blocks added
179  *
180  *  @description
181  *  This function add WLS blocks to the L1 Array which will be used by L1 in 
182  *  every TTI to populate and send back APIs to the MAC
183  *
184 **/
185 //------------------------------------------------------------------------------
186 uint8_t wls_fapi_add_blocks_to_ul(
187     void)
188 {
189     int num_blocks = 0;
190     p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
191     WLS_HANDLE h_wls = pWls->h_wls[NR5G_FAPI2PHY_WLS_INST];
192
193     void *pMsg = wls_fapi_alloc_buffer(0, MIN_UL_BUF_LOCATIONS);
194     if (!pMsg) {
195         return num_blocks;
196     }
197
198     /* allocate blocks for UL transmittion */
199     while (WLS_EnqueueBlock(h_wls, nr5g_fapi_wls_va_to_pa(h_wls, pMsg)) > 0) {
200         num_blocks++;
201         pMsg = wls_fapi_alloc_buffer(0, MIN_UL_BUF_LOCATIONS);
202         if (!pMsg)
203             break;
204     }
205
206     // free not enqueued block
207     if (pMsg) {
208         wls_fapi_free_buffer(pMsg, MIN_UL_BUF_LOCATIONS);
209     }
210
211     return num_blocks;
212 }
213
214 //------------------------------------------------------------------------------
215 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
216  *
217  *  @param          A pointer to the phy instance table.
218  *
219  *  @return         0 if SUCCESS
220  *
221  *  @description    This function initializes WLS layer primitives and allocates
222  *                  memory needed to exchange APIs between FAPI and PHY.
223 **/
224 //------------------------------------------------------------------------------
225 uint8_t nr5g_fapi_wls_init(
226     p_nr5g_fapi_cfg_t cfg)
227 {
228     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
229     const char *dev_name = "wls";
230
231     if (p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST] &&
232         p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST]) {
233         // NR5G_FAPI_LOG(ERROR_LOG, ("WLS instance already opened!"));
234         return FAILURE;
235     }
236
237     p_wls_ctx->shmem_size = cfg->wls.shmem_size;
238     p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST] =
239         WLS_Open_Dual(dev_name /*"wls"cfg->wls.device_name */ ,
240         WLS_SLAVE_CLIENT,
241         cfg->wls.shmem_size, &p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST]);
242     if ((NULL == p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST]) &&
243         (NULL == p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST])) {
244         // NR5G_FAPI_LOG(ERROR_LOG,("[NR5G_FAPI_ WLS] WLS instance connected."));
245         return FAILURE;
246     }
247     // Issue WLS_Alloc() for FAPI2MAC
248     p_wls_ctx->shmem = WLS_Alloc(p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST],
249         p_wls_ctx->shmem_size);
250
251     if (NULL == p_wls_ctx->shmem) {
252         printf("Unable to alloc WLS Memory for FAPI2MAC\n");
253         return FAILURE;
254     }
255
256     p_wls_ctx->shmem = WLS_Alloc(p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST],
257         p_wls_ctx->shmem_size);
258     p_wls_ctx->pWlsMemBase = p_wls_ctx->shmem;
259     p_wls_ctx->nTotalMemorySize = p_wls_ctx->shmem_size;
260     if (NULL == p_wls_ctx->shmem) {
261         printf("Unable to alloc WLS Memory\n");
262         return FAILURE;
263     }
264
265     pthread_mutex_init((pthread_mutex_t *)
266             &p_wls_ctx->fapi2phy_lock_send, NULL);
267     pthread_mutex_init((pthread_mutex_t *)
268             &p_wls_ctx->fapi2phy_lock_alloc, NULL);
269     pthread_mutex_init((pthread_mutex_t *)
270             &p_wls_ctx->fapi2mac_lock_send, NULL);
271     pthread_mutex_init((pthread_mutex_t *)
272             &p_wls_ctx->fapi2mac_lock_alloc, NULL);
273     return SUCCESS;
274 }
275
276 //-------------------------------------------------------------------------------------------
277 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
278  *
279  *  @param[in]   pMemArray Pointer to WLS Memory Management Structure
280  *  @param[in]   pMemArrayMmeory pointer to flat buffer that was allocated
281  *  @param[in]   totalSize total size of flat buffer allocated
282  *  @param[in]   nBlockSize Size of each block that needs to be partitoned by the memory manager
283  *
284  *  @return  0 if SUCCESS
285  *
286  *  @description
287  *  This function creates memory blocks from a flat buffer which will be used for communication between FAPI and PHY
288  *
289 **/
290 //-------------------------------------------------------------------------------------------
291 uint32_t wls_fapi_create_mem_array(
292     PWLS_FAPI_MEM_STRUCT pMemArray,
293     void *pMemArrayMemory,
294     uint32_t totalSize,
295     uint32_t nBlockSize)
296 {
297
298     int numBlocks = totalSize / nBlockSize;
299     void **ptr;
300     uint32_t i;
301
302     printf
303         ("wls_fapi_create_mem_array: pMemArray[%p] pMemArrayMemory[%p] totalSize[%d] nBlockSize[%d] numBlocks[%d]\n",
304         pMemArray, pMemArrayMemory, totalSize, nBlockSize, numBlocks);
305
306     // Can't be less than pointer size
307     if (nBlockSize < sizeof(void *)) {
308         return FAILURE;
309     }
310     // Can't be less than one block
311     if (totalSize < sizeof(void *)) {
312         return FAILURE;
313     }
314
315     pMemArray->ppFreeBlock = (void **)pMemArrayMemory;
316     pMemArray->pStorage = pMemArrayMemory;
317     pMemArray->pEndOfStorage =
318         ((unsigned long *)pMemArrayMemory) +
319         numBlocks * nBlockSize / sizeof(unsigned long);
320     pMemArray->nBlockSize = nBlockSize;
321     pMemArray->nBlockCount = numBlocks;
322
323     // Initialize single-linked list of free blocks;
324     ptr = (void **)pMemArrayMemory;
325     for (i = 0; i < pMemArray->nBlockCount; i++) {
326 #ifdef MEMORY_CORRUPTION_DETECT
327         // Fill with some pattern
328         uint8_t *p = (uint8_t *) ptr;
329         uint32_t j;
330
331         p += (nBlockSize - 16);
332         for (j = 0; j < 16; j++) {
333             p[j] = MEMORY_CORRUPTION_DETECT_FLAG;
334         }
335 #endif
336
337         if (i == pMemArray->nBlockCount - 1) {
338             *ptr = NULL;        // End of list
339         } else {
340             // Points to the next block
341             *ptr = (void **)(((uint8_t *) ptr) + nBlockSize);
342             ptr += nBlockSize / sizeof(unsigned long);
343         }
344     }
345
346     NR5G_FAPI_MEMSET(alloc_track, sizeof(uint8_t) * ALLOC_TRACK_SIZE, 0,
347         sizeof(uint8_t) * ALLOC_TRACK_SIZE);
348
349     return SUCCESS;
350 }
351
352 //-------------------------------------------------------------------------------------------
353 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
354  *
355  *  @param[in]   pWls Pointer to the nr5g_fapi_wls_ctx structure
356  *
357  *  @return  0 if SUCCESS
358  *
359  *  @description
360  *  This function created a partition and blocks of WLS memory for API exchange between FAPI and PHY
361  *
362 **/
363 //-------------------------------------------------------------------------------------------
364 int wls_fapi_create_partition(
365     p_nr5g_fapi_wls_context_t pWls)
366 {
367 #define WLS_HUGE_DEF_PAGE_SIZEA    0x40000000LL
368     static long hugePageSize = WLS_HUGE_DEF_PAGE_SIZEA;
369     //   NR5G_FAPI_MEMSET(pWls->pWlsMemBase , 0xCC, pWls->nTotalMemorySize);  // This is done by the Master Only
370     pWls->pPartitionMemBase =
371         (void *)(((uint8_t *) pWls->pWlsMemBase) + hugePageSize);
372     pWls->nPartitionMemSize = (pWls->nTotalMemorySize - hugePageSize);
373
374     pWls->nTotalBlocks = pWls->nPartitionMemSize / MSG_MAXSIZE;
375     return wls_fapi_create_mem_array(&pWls->sWlsStruct, pWls->pPartitionMemBase,
376         pWls->nPartitionMemSize, MSG_MAXSIZE);
377 }
378
379 //------------------------------------------------------------------------------
380 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
381  *
382  *  @param[in]      A pointer to the FAPI Memory Structure (Initialized by L2)
383  *  @param[out]     ppBlock Pointer where the allocated memory block is stored     
384  *
385  *  @return         0 if SUCCESS
386  *
387  *  @description    This function allocates a memory block from the pool
388  *
389 **/
390 //------------------------------------------------------------------------------
391 uint32_t wls_fapi_alloc_mem_array(
392     PWLS_FAPI_MEM_STRUCT pMemArray,
393     void **ppBlock)
394 {
395     int idx;
396
397     if (pMemArray->ppFreeBlock == NULL) {
398         printf("wls_fapi_alloc_mem_array pMemArray->ppFreeBlock = NULL\n");
399         return FAILURE;
400     }
401     // FIXME: Remove after debugging
402     if (((void *)pMemArray->ppFreeBlock < pMemArray->pStorage) ||
403         ((void *)pMemArray->ppFreeBlock >= pMemArray->pEndOfStorage)) {
404         printf
405             ("wls_fapi_alloc_mem_array ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
406             pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock);
407         return FAILURE;
408     }
409
410     pMemArray->ppFreeBlock =
411         (void **)((unsigned long)pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
412     *pMemArray->ppFreeBlock =
413         (void **)((unsigned long)*pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
414
415     if ((*pMemArray->ppFreeBlock != NULL) &&
416         (((*pMemArray->ppFreeBlock) < pMemArray->pStorage) ||
417             ((*pMemArray->ppFreeBlock) >= pMemArray->pEndOfStorage))) {
418         fprintf(stderr,
419             "ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
420             pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
421             *pMemArray->ppFreeBlock);
422         return FAILURE;
423     }
424
425     *ppBlock = (void *)pMemArray->ppFreeBlock;
426     pMemArray->ppFreeBlock = (void **)(*pMemArray->ppFreeBlock);
427
428     idx =
429         (((uint64_t) * ppBlock -
430             (uint64_t) pMemArray->pStorage)) / pMemArray->nBlockSize;
431     if (alloc_track[idx]) {
432         printf
433             ("wls_fapi_alloc_mem_array Double alloc Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
434             pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
435             *pMemArray->ppFreeBlock);
436         return FAILURE;
437     } else {
438 #ifdef MEMORY_CORRUPTION_DETECT
439         uint32_t nBlockSize = pMemArray->nBlockSize, i;
440         uint8_t *p = (uint8_t *) * ppBlock;
441
442         p += (nBlockSize - 16);
443         for (i = 0; i < 16; i++) {
444             p[i] = MEMORY_CORRUPTION_DETECT_FLAG;
445         }
446 #endif
447         alloc_track[idx] = 1;
448     }
449
450     //printf("Block allocd [%p,%p]\n", pMemArray, *ppBlock);
451
452     return SUCCESS;
453 }
454
455 //------------------------------------------------------------------------------
456 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
457  *
458  *  @param[in]      A pointer to the FAPI Memory Structure (Initialized by L2)
459  *  @param[in]      pBlock Pointer where the allocated memory block is stored     
460  *
461  *  @return         0 if SUCCESS
462  *
463  *  @description    This function frees a WLS block of memory and adds 
464  *                  it back to the pool
465  *
466 **/
467 //------------------------------------------------------------------------------
468 uint32_t wls_fapi_free_mem_array(
469     PWLS_FAPI_MEM_STRUCT pMemArray,
470     void *pBlock)
471 {
472     int idx;
473     unsigned long mask = (((unsigned long)pMemArray->nBlockSize) - 1);
474
475     pBlock = (void *)((unsigned long)pBlock & ~mask);
476
477     if ((pBlock < pMemArray->pStorage) || (pBlock >= pMemArray->pEndOfStorage)) {
478         printf
479             ("wls_fapi_free_mem_array WARNING: Trying to free foreign block;Arr=%p,Blk=%p pStorage [%p .. %p]\n",
480             pMemArray, pBlock, pMemArray->pStorage, pMemArray->pEndOfStorage);
481         return FAILURE;
482     }
483
484     idx =
485         (int)(((uint64_t) pBlock -
486             (uint64_t) pMemArray->pStorage)) / pMemArray->nBlockSize;
487
488     if (alloc_track[idx] == 0) {
489         printf
490             ("wls_fapi_free_mem_array ERROR: Double free Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
491             pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock, pBlock);
492         return SUCCESS;
493     } else {
494 #ifdef MEMORY_CORRUPTION_DETECT
495         uint32_t nBlockSize = pMemArray->nBlockSize, i;
496         uint8_t *p = (uint8_t *) pBlock;
497
498         p += (nBlockSize - 16);
499         for (i = 0; i < 16; i++) {
500             if (p[i] != MEMORY_CORRUPTION_DETECT_FLAG) {
501                 printf("ERROR: Corruption\n");
502                 nr5g_fapi_wls_print_stats();
503                 exit(-1);
504             }
505         }
506 #endif
507         alloc_track[idx] = 0;
508     }
509
510     if (((void *)pMemArray->ppFreeBlock) == pBlock) {
511         // Simple protection against freeing of already freed block
512         return SUCCESS;
513     }
514     // FIXME: Remove after debugging
515     if ((pMemArray->ppFreeBlock != NULL)
516         && (((void *)pMemArray->ppFreeBlock < pMemArray->pStorage)
517             || ((void *)pMemArray->ppFreeBlock >= pMemArray->pEndOfStorage))) {
518         printf
519             ("wls_fapi_free_mem_array ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
520             pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock);
521         return FAILURE;
522     }
523     // FIXME: Remove after debugging
524     if ((pBlock < pMemArray->pStorage) || (pBlock >= pMemArray->pEndOfStorage)) {
525         printf("wls_fapi_free_mem_array ERROR: Invalid block;Arr=%p,Blk=%p\n",
526             pMemArray, pBlock);
527         return FAILURE;
528     }
529
530     *((void **)pBlock) =
531         (void **)((unsigned long)pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
532     pMemArray->ppFreeBlock =
533         (void **)((unsigned long)pBlock & 0xFFFFFFFFFFFFFFF0);
534
535     //printf("Block freed [%p,%p]\n", pMemArray, pBlock);
536
537     return SUCCESS;
538 }
539
540 //------------------------------------------------------------------------------
541 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
542  *
543  *  @param          size (if 0 fixed size from pool)
544  *  @param          Number of locations
545  *
546  *  @return         0 if SUCCESS
547  *
548  *  @description    This function initializes WLS layer primitives and allocates
549  *                  memory needed to exchange APIs between FAPI and PHY.
550 **/
551 //------------------------------------------------------------------------------
552 void *wls_fapi_alloc_buffer(
553     uint32_t size,
554     uint32_t loc)
555 {
556     void *pBlock = NULL;
557     p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
558
559     if (pthread_mutex_lock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
560         NR5G_FAPI_LOG(ERROR_LOG, ("unable to get lock alloc pthread mutex"));
561         exit(-1);
562     }
563
564     if (wls_fapi_alloc_mem_array(&pWls->sWlsStruct, &pBlock) != SUCCESS) {
565         printf("wls_fapi_alloc_buffer alloc error size[%d] loc[%d]\n", size,
566             loc);
567         nr5g_fapi_wls_print_stats();
568         exit(-1);
569     } else {
570         pWls->nAllocBlocks++;
571     }
572
573     //printf("----------------wls_fapi_alloc_buffer: size[%d] loc[%d] buf[%p] nAllocBlocks[%d]\n", size, loc, pBlock, pWls->nAllocBlocks);
574
575     //printf("[%p]\n", pBlock);
576
577     pWls->nTotalAllocCnt++;
578     if (loc < MAX_DL_BUF_LOCATIONS)
579         pWls->nTotalDlBufAllocCnt[loc]++;
580     else if (loc < MAX_UL_BUF_LOCATIONS)
581         pWls->nTotalUlBufAllocCnt++;
582
583     if (pthread_mutex_unlock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
584         NR5G_FAPI_LOG(ERROR_LOG, ("unable to unlock alloc pthread mutex"));
585         exit(-1);
586     }
587
588     return pBlock;
589 }
590
591 //------------------------------------------------------------------------------
592 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
593  *
594  *  @param[in]      *pMsg Pointer to free
595  *
596  *  @return         void
597  *
598  *  @descriptioni   This function frees a block of memory and adds it back to 
599  *                  the pool.
600  *
601 **/
602 //------------------------------------------------------------------------------
603 void wls_fapi_free_buffer(
604     void *pMsg,
605     uint32_t loc)
606 {
607     p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
608
609     if (pthread_mutex_lock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
610         NR5G_FAPI_LOG(ERROR_LOG, ("unable to lock alloc pthread mutex"));
611         exit(-1);
612     }
613     //printf("----------------wls_fapi_free_buffer: buf[%p] loc[%d]\n", pMsg, loc);
614     if (wls_fapi_free_mem_array(&pWls->sWlsStruct, (void *)pMsg) == SUCCESS) {
615         pWls->nAllocBlocks--;
616     } else {
617         printf("wls_fapi_free_buffer Free error\n");
618         nr5g_fapi_wls_print_stats();
619         exit(-1);
620     }
621
622     pWls->nTotalFreeCnt++;
623     if (loc < MAX_DL_BUF_LOCATIONS)
624         pWls->nTotalDlBufFreeCnt[loc]++;
625     else if (loc < MAX_UL_BUF_LOCATIONS)
626         pWls->nTotalUlBufFreeCnt++;
627
628     if (pthread_mutex_unlock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
629         NR5G_FAPI_LOG(ERROR_LOG, ("unable to unlock alloc pthread mutex"));
630         exit(-1);
631     }
632 }
633
634 //------------------------------------------------------------------------------
635 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
636  *
637  *  @param          A pointer to a wls instance
638  *
639  *  @return         0 if SUCCESS
640  *
641  *  @description    This function initializes the WLS layer FAPI2PHY interface 
642  *                  primitives and allocates memory needed to exchange APIs 
643  *                  between FAPI and PHY.
644 **/
645 //------------------------------------------------------------------------------
646 uint8_t nr5g_fapi2Phy_wls_init(
647     p_nr5g_fapi_wls_context_t pwls)
648 {
649     int nBlocks = 0;
650     uint8_t retval = SUCCESS;
651
652     retval = wls_fapi_create_partition(pwls);
653     if ((nBlocks = wls_fapi_add_blocks_to_ul()) == 0) {
654         return FAILURE;
655     }
656
657     return retval;
658 }
659
660 uint8_t get_stats_location(
661     uint8_t msg_type)
662 {
663     uint8_t loc;
664     switch (msg_type) {
665         case MSG_TYPE_PHY_CONFIG_REQ:
666             loc = MEM_STAT_CONFIG_REQ;
667             break;
668         case MSG_TYPE_PHY_START_REQ:
669             loc = MEM_STAT_START_REQ;
670             break;
671         case MSG_TYPE_PHY_STOP_REQ:
672             loc = MEM_STAT_STOP_REQ;
673             break;
674         case MSG_TYPE_PHY_SHUTDOWN_REQ:
675             loc = MEM_STAT_SHUTDOWN_REQ;
676             break;
677         case MSG_TYPE_PHY_DL_CONFIG_REQ:
678             loc = MEM_STAT_DL_CONFIG_REQ;
679             break;
680         case MSG_TYPE_PHY_UL_CONFIG_REQ:
681             loc = MEM_STAT_UL_CONFIG_REQ;
682             break;
683         case MSG_TYPE_PHY_UL_DCI_REQ:
684             loc = MEM_STAT_UL_DCI_REQ;
685             break;
686         case MSG_TYPE_PHY_TX_REQ:
687             loc = MEM_STAT_TX_REQ;
688             break;
689         case MSG_TYPE_PHY_DL_IQ_SAMPLES:
690             loc = MEM_STAT_DL_IQ_SAMPLES;
691             break;
692         case MSG_TYPE_PHY_UL_IQ_SAMPLES:
693             loc = MEM_STAT_UL_IQ_SAMPLES;
694             break;
695         default:
696             loc = MEM_STAT_DEFAULT;
697     }
698
699     return loc;
700 }
701
702 //------------------------------------------------------------------------------
703 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
704  *
705  *  @param[in]      pListElem Pointer to List element header
706  *  @param[in]      idx Subframe Number
707  *
708  *  @return         Number of blocks freed
709  *
710  *  @description    This function Frees all the blocks in a List Element Linked
711  *                  List coming from L1 by storing them into an array to be 
712  *                  freed at a later point in time.
713 **/
714 //------------------------------------------------------------------------------
715 void wls_fapi_add_recv_apis_to_free(
716     PMAC2PHY_QUEUE_EL pListElem,
717     uint32_t idx)
718 {
719     PMAC2PHY_QUEUE_EL pNextMsg = NULL;
720     L1L2MessageHdr *p_msg_header = NULL;
721     PRXULSCHIndicationStruct p_phy_rx_ulsch_ind = NULL;
722     int count, i;
723     uint8_t *ptr = NULL;
724
725     WLS_HANDLE h_wls;
726     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
727     h_wls = p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST];
728
729     count = g_to_free_recv_list_cnt[idx];
730     pNextMsg = pListElem;
731     while (pNextMsg) {
732         if (count >= TOTAL_FREE_BLOCKS) {
733             NR5G_FAPI_LOG(ERROR_LOG, ("%s: Reached max capacity of free list.\n"
734                     "\t\t\t\tlist index: %d list count: %d max list count: %d",
735                     __func__, idx, count, TOTAL_FREE_BLOCKS));
736             return;
737         }
738
739         g_to_free_recv_list[idx][count++] = (uint64_t) pNextMsg;
740         p_msg_header = (PL1L2MessageHdr) (pNextMsg + 1);
741         if (p_msg_header->nMessageType == MSG_TYPE_PHY_RX_ULSCH_IND) {
742             p_phy_rx_ulsch_ind = (PRXULSCHIndicationStruct) p_msg_header;
743             for (i = 0; i < p_phy_rx_ulsch_ind->nUlsch; i++) {
744                 ptr = p_phy_rx_ulsch_ind->sULSCHPDUDataStruct[i].pPayload;
745                 ptr = (uint8_t *) nr5g_fapi_wls_pa_to_va(h_wls, (uint64_t) ptr);
746
747                 if (ptr) {
748                     g_to_free_recv_list[idx][count++] = (uint64_t) ptr;
749                 }
750             }
751         }
752         pNextMsg = pNextMsg->pNext;
753     }
754
755     g_to_free_recv_list[idx][count] = 0L;
756     g_to_free_recv_list_cnt[idx] = count;
757
758     NR5G_FAPI_LOG(DEBUG_LOG, ("To Free %d\n", count));
759 }
760
761 //------------------------------------------------------------------------------
762 /** @ingroup nr5g_fapi_source_framework_wls_lib_group 
763  *
764  *  @param[in]      idx subframe Number
765  *
766  *  @return         Number of blocks freed
767  *
768  *  @description    This function frees all blocks that have been added to the 
769  *                  free array
770 **/
771 //------------------------------------------------------------------------------
772 void wls_fapi_free_recv_free_list(
773     uint32_t idx)
774 {
775     PMAC2PHY_QUEUE_EL pNextMsg = NULL;
776     int count = 0;
777
778     if (idx >= TO_FREE_SIZE) {
779         NR5G_FAPI_LOG(ERROR_LOG, ("%s: list index: %d\n", __func__, idx));
780         return;
781     }
782
783     pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_recv_list[idx][count];
784     while (pNextMsg) {
785         wls_fapi_free_buffer(pNextMsg, MIN_UL_BUF_LOCATIONS);
786         g_to_free_recv_list[idx][count++] = 0L;
787         if (g_to_free_recv_list[idx][count])
788             pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_recv_list[idx][count];
789         else
790             pNextMsg = 0L;
791     }
792
793     NR5G_FAPI_LOG(DEBUG_LOG, ("Free %d\n", count));
794     g_to_free_recv_list_cnt[idx] = 0;
795
796     return;
797 }
798
799 //------------------------------------------------------------------------------
800 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
801  *
802  *  @param[in]      pListElem Pointer to List element header
803  *  @param[in]      idx Subframe Number
804  *
805  *  @return         Number of blocks freed
806  *
807  *  @description    This function Frees all the blocks in a List Element Linked
808  *                  List coming from L1 by storing them into an array to be 
809  *                  freed at a later point in time.
810 **/
811 //------------------------------------------------------------------------------
812 void wls_fapi_add_send_apis_to_free(
813     PMAC2PHY_QUEUE_EL pListElem,
814     uint32_t idx)
815 {
816     PMAC2PHY_QUEUE_EL pNextMsg = NULL;
817     L1L2MessageHdr *p_msg_header = NULL;
818     PRXULSCHIndicationStruct p_phy_rx_ulsch_ind = NULL;
819     int count, i;
820     uint8_t *ptr = NULL;
821
822     count = g_to_free_send_list_cnt[idx];
823     pNextMsg = pListElem;
824     while (pNextMsg) {
825         if (count >= TOTAL_FREE_BLOCKS) {
826             NR5G_FAPI_LOG(ERROR_LOG, ("%s: Reached max capacity of free list.\n"
827                     "\t\t\t\tlist index: %d list count: %d max list count: %d",
828                     __func__, idx, count, TOTAL_FREE_BLOCKS));
829             return;
830         }
831
832         g_to_free_send_list[idx][count++] = (uint64_t) pNextMsg;
833         p_msg_header = (PL1L2MessageHdr) (pNextMsg + 1);
834         if (p_msg_header->nMessageType == MSG_TYPE_PHY_RX_ULSCH_IND) {
835             p_phy_rx_ulsch_ind = (PRXULSCHIndicationStruct) p_msg_header;
836             for (i = 0; i < p_phy_rx_ulsch_ind->nUlsch; i++) {
837                 ptr = p_phy_rx_ulsch_ind->sULSCHPDUDataStruct[i].pPayload;
838                 if (ptr) {
839                     g_to_free_send_list[idx][count++] = (uint64_t) ptr;
840                 }
841             }
842         }
843         pNextMsg = pNextMsg->pNext;
844     }
845
846     g_to_free_send_list[idx][count] = 0L;
847     g_to_free_send_list_cnt[idx] = count;
848
849     NR5G_FAPI_LOG(DEBUG_LOG, ("To Free %d\n", count));
850 }
851
852 //------------------------------------------------------------------------------
853 /** @ingroup nr5g_fapi_source_framework_wls_lib_group 
854  *
855  *  @param[in]      idx subframe Number
856  *
857  *  @return         Number of blocks freed
858  *
859  *  @description    This function frees all blocks that have been added to the 
860  *                  free array
861 **/
862 //------------------------------------------------------------------------------
863 void wls_fapi_free_send_free_list(
864     uint32_t idx)
865 {
866     PMAC2PHY_QUEUE_EL pNextMsg = NULL;
867     L1L2MessageHdr *p_msg_header = NULL;
868     int count = 0, loc = 0;
869
870     if (idx >= TO_FREE_SIZE) {
871         NR5G_FAPI_LOG(ERROR_LOG, ("%s: list index: %d\n", __func__, idx));
872         return;
873     }
874
875     pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_send_list[idx][count];
876     while (pNextMsg) {
877         p_msg_header = (PL1L2MessageHdr) (pNextMsg + 1);
878         loc = get_stats_location(p_msg_header->nMessageType);
879         wls_fapi_free_buffer(pNextMsg, loc);
880         g_to_free_send_list[idx][count++] = 0L;
881         if (g_to_free_send_list[idx][count])
882             pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_send_list[idx][count];
883         else
884             pNextMsg = 0L;
885     }
886
887     NR5G_FAPI_LOG(DEBUG_LOG, ("Free %d\n", count));
888     g_to_free_send_list_cnt[idx] = 0;
889
890     return;
891 }
892
893 //------------------------------------------------------------------------------
894 /** @ingroup nr5g_fapi_source_framework_wls_lib_group 
895  *
896  *  @param[in]      idx subframe Number
897  *
898  *  @return         Number of blocks freed
899  *
900  *  @description    This function frees all blocks that have been added to the 
901  *                  free array
902 **/
903 //------------------------------------------------------------------------------
904 void wls_fapi_free_list_all(
905     void)
906 {
907     uint32_t idx;
908
909     for (idx = 0; idx < TO_FREE_SIZE; idx++) {
910         wls_fapi_free_send_free_list(idx);
911         wls_fapi_free_recv_free_list(idx);
912     }
913
914     nr5g_fapi_wls_print_stats();
915 }