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