--- /dev/null
+/******************************************************************************
+*
+* Copyright (c) 2019 Intel.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*******************************************************************************/
+
+/**
+ * @file This file has Shared Memory interface functions between FAPI and PHY
+ * @defgroup nr5g_fapi_source_framework_wls_lib_group
+ **/
+
+#include "nr5g_fapi_framework.h"
+#include "nr5g_fapi_internal.h"
+#include "nr5g_fapi_wls.h"
+#include "nr5g_fapi_config_loader.h"
+#include "nr5g_fapi_log.h"
+#include "nr5g_fapi_memory.h"
+
+nr5g_fapi_wls_context_t g_wls_ctx;
+
+static uint32_t g_to_free_send_list_cnt[TO_FREE_SIZE] = { 0 };
+static uint64_t g_to_free_send_list[TO_FREE_SIZE][TOTAL_FREE_BLOCKS] = { {0L} };
+static uint32_t g_to_free_recv_list_cnt[TO_FREE_SIZE] = { 0 };
+static uint64_t g_to_free_recv_list[TO_FREE_SIZE][TOTAL_FREE_BLOCKS] = { {0L} };
+
+static uint8_t alloc_track[ALLOC_TRACK_SIZE];
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param void
+ *
+ * @return A pointer to WLS Context stucture
+ *
+ * @description
+ * This function returns the WLS Context structure which has WLS related parameters
+ *
+**/
+//------------------------------------------------------------------------------
+inline p_nr5g_fapi_wls_context_t nr5g_fapi_wls_context(
+ )
+{
+ return &g_wls_ctx;
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] ptr Pointer to display
+ * @param[in] size Size of data
+ *
+ * @return void
+ *
+ * @description
+ * This function displays content of Buffer - Used for debugging
+ *
+**/
+//------------------------------------------------------------------------------
+void nr5g_fapi_wls_show_data(
+ void *ptr,
+ uint32_t size)
+{
+ uint8_t *d = ptr;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (!(i & 0xf))
+ printf("\n");
+ printf("%02x ", d[i]);
+ }
+ printf("\n");
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param N/A
+ *
+ * @return N/A
+ *
+ * @description
+ * This function prints to the console FAPI stats
+ *
+**/
+//------------------------------------------------------------------------------
+void nr5g_fapi_wls_print_stats(
+ void)
+{
+ p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
+ printf(" nTotalBlocks[%5d] nAllocBlocks[%5d] nFreeBlocks[%5d]\n",
+ pWls->nTotalBlocks, pWls->nAllocBlocks,
+ (pWls->nTotalBlocks - pWls->nAllocBlocks));
+ printf(" nTotalAllocCnt[%5d] nTotalFreeCnt[%5d] Diff[%5d]\n",
+ pWls->nTotalAllocCnt, pWls->nTotalFreeCnt,
+ (pWls->nTotalAllocCnt - pWls->nTotalFreeCnt));
+ uint32_t nFinalTotalDlBufAllocCnt = 0, nFinalTotalDlBufFreeCnt = 0, idx;
+
+//#define PRINTF_DEBUG(fmt, args...) //printf(fmt, ## args)
+#define PRINTF_DEBUG(fmt, args...)
+ PRINTF_DEBUG("\n");
+ PRINTF_DEBUG("\n nDlBufAllocCnt: \n");
+ for (idx = 0; idx < MEM_STAT_DEFAULT; idx++) {
+ nFinalTotalDlBufAllocCnt += pWls->nTotalDlBufAllocCnt[idx];
+ PRINTF_DEBUG("[%3d:%5d] ", idx, pWls->nTotalDlBufAllocCnt[idx]);
+ }
+ PRINTF_DEBUG("\n");
+ PRINTF_DEBUG("\n nDlBufFreeCnt: \n");
+ for (idx = 0; idx < MEM_STAT_DEFAULT; idx++) {
+ nFinalTotalDlBufFreeCnt += pWls->nTotalDlBufFreeCnt[idx];
+ PRINTF_DEBUG("[%3d:%5d] ", idx, pWls->nTotalDlBufFreeCnt[idx]);
+ }
+ PRINTF_DEBUG("\n\n");
+
+ printf(" nDlBufAllocCnt[%5d] nDlBufFreeCnt[%5d] Diff[%5d]\n",
+ nFinalTotalDlBufAllocCnt, nFinalTotalDlBufFreeCnt,
+ (nFinalTotalDlBufAllocCnt - nFinalTotalDlBufFreeCnt));
+ printf
+ (" nUlBufAllocCnt[%5d] nUlBufFreeCnt[%5d] Diff[%5d]\n\n",
+ pWls->nTotalUlBufAllocCnt, pWls->nTotalUlBufFreeCnt,
+ (pWls->nTotalUlBufAllocCnt - pWls->nTotalUlBufFreeCnt));
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] ptr Address to convert
+ *
+ * @return Converted address
+ *
+ * @description
+ * This function converts Virtual Address to Physical Address
+ *
+**/
+//------------------------------------------------------------------------------
+uint64_t nr5g_fapi_wls_va_to_pa(
+ WLS_HANDLE h_wls,
+ void *ptr)
+{
+ return ((uint64_t) WLS_VA2PA(h_wls, ptr));
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] ptr Address to convert
+ *
+ * @return Converted address
+ *
+ * @description
+ * This function converts Physical Address to Virtual Address
+ *
+**/
+//------------------------------------------------------------------------------
+void *nr5g_fapi_wls_pa_to_va(
+ WLS_HANDLE h_wls,
+ uint64_t ptr)
+{
+ return ((void *)WLS_PA2VA(h_wls, ptr));
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param void
+ *
+ * @return Number of blocks added
+ *
+ * @description
+ * This function add WLS blocks to the L1 Array which will be used by L1 in
+ * every TTI to populate and send back APIs to the MAC
+ *
+**/
+//------------------------------------------------------------------------------
+uint8_t wls_fapi_add_blocks_to_ul(
+ void)
+{
+ int num_blocks = 0;
+ p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
+ WLS_HANDLE h_wls = pWls->h_wls[NR5G_FAPI2PHY_WLS_INST];
+
+ void *pMsg = wls_fapi_alloc_buffer(0, MIN_UL_BUF_LOCATIONS);
+ if (!pMsg) {
+ return num_blocks;
+ }
+
+ /* allocate blocks for UL transmittion */
+ while (WLS_EnqueueBlock(h_wls, nr5g_fapi_wls_va_to_pa(h_wls, pMsg)) > 0) {
+ num_blocks++;
+ pMsg = wls_fapi_alloc_buffer(0, MIN_UL_BUF_LOCATIONS);
+ if (!pMsg)
+ break;
+ }
+
+ // free not enqueued block
+ if (pMsg) {
+ wls_fapi_free_buffer(pMsg, MIN_UL_BUF_LOCATIONS);
+ }
+
+ return num_blocks;
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param A pointer to the phy instance table.
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description This function initializes WLS layer primitives and allocates
+ * memory needed to exchange APIs between FAPI and PHY.
+**/
+//------------------------------------------------------------------------------
+uint8_t nr5g_fapi_wls_init(
+ p_nr5g_fapi_cfg_t cfg)
+{
+ p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
+ const char *dev_name = "wls";
+
+ if (p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST] &&
+ p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST]) {
+ // NR5G_FAPI_LOG(ERROR_LOG, ("WLS instance already opened!"));
+ return FAILURE;
+ }
+
+ p_wls_ctx->shmem_size = cfg->wls.shmem_size;
+ p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST] =
+ WLS_Open_Dual(dev_name /*"wls"cfg->wls.device_name */ ,
+ WLS_SLAVE_CLIENT,
+ cfg->wls.shmem_size, &p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST]);
+ if ((NULL == p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST]) &&
+ (NULL == p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST])) {
+ // NR5G_FAPI_LOG(ERROR_LOG,("[NR5G_FAPI_ WLS] WLS instance connected."));
+ return FAILURE;
+ }
+ // Issue WLS_Alloc() for FAPI2MAC
+ p_wls_ctx->shmem = WLS_Alloc(p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST],
+ p_wls_ctx->shmem_size);
+
+ if (NULL == p_wls_ctx->shmem) {
+ printf("Unable to alloc WLS Memory for FAPI2MAC\n");
+ return FAILURE;
+ }
+
+ p_wls_ctx->shmem = WLS_Alloc(p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST],
+ p_wls_ctx->shmem_size);
+ p_wls_ctx->pWlsMemBase = p_wls_ctx->shmem;
+ p_wls_ctx->nTotalMemorySize = p_wls_ctx->shmem_size;
+ if (NULL == p_wls_ctx->shmem) {
+ printf("Unable to alloc WLS Memory\n");
+ return FAILURE;
+ }
+
+ pthread_mutex_init((pthread_mutex_t *)
+ &p_wls_ctx->fapi2phy_lock_send, NULL);
+ pthread_mutex_init((pthread_mutex_t *)
+ &p_wls_ctx->fapi2phy_lock_alloc, NULL);
+ pthread_mutex_init((pthread_mutex_t *)
+ &p_wls_ctx->fapi2mac_lock_send, NULL);
+ pthread_mutex_init((pthread_mutex_t *)
+ &p_wls_ctx->fapi2mac_lock_alloc, NULL);
+ return SUCCESS;
+}
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] pMemArray Pointer to WLS Memory Management Structure
+ * @param[in] pMemArrayMmeory pointer to flat buffer that was allocated
+ * @param[in] totalSize total size of flat buffer allocated
+ * @param[in] nBlockSize Size of each block that needs to be partitoned by the memory manager
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function creates memory blocks from a flat buffer which will be used for communication between FAPI and PHY
+ *
+**/
+//-------------------------------------------------------------------------------------------
+uint32_t wls_fapi_create_mem_array(
+ PWLS_FAPI_MEM_STRUCT pMemArray,
+ void *pMemArrayMemory,
+ uint32_t totalSize,
+ uint32_t nBlockSize)
+{
+
+ int numBlocks = totalSize / nBlockSize;
+ void **ptr;
+ uint32_t i;
+
+ printf
+ ("wls_fapi_create_mem_array: pMemArray[%p] pMemArrayMemory[%p] totalSize[%d] nBlockSize[%d] numBlocks[%d]\n",
+ pMemArray, pMemArrayMemory, totalSize, nBlockSize, numBlocks);
+
+ // Can't be less than pointer size
+ if (nBlockSize < sizeof(void *)) {
+ return FAILURE;
+ }
+ // Can't be less than one block
+ if (totalSize < sizeof(void *)) {
+ return FAILURE;
+ }
+
+ pMemArray->ppFreeBlock = (void **)pMemArrayMemory;
+ pMemArray->pStorage = pMemArrayMemory;
+ pMemArray->pEndOfStorage =
+ ((unsigned long *)pMemArrayMemory) +
+ numBlocks * nBlockSize / sizeof(unsigned long);
+ pMemArray->nBlockSize = nBlockSize;
+ pMemArray->nBlockCount = numBlocks;
+
+ // Initialize single-linked list of free blocks;
+ ptr = (void **)pMemArrayMemory;
+ for (i = 0; i < pMemArray->nBlockCount; i++) {
+#ifdef MEMORY_CORRUPTION_DETECT
+ // Fill with some pattern
+ uint8_t *p = (uint8_t *) ptr;
+ uint32_t j;
+
+ p += (nBlockSize - 16);
+ for (j = 0; j < 16; j++) {
+ p[j] = MEMORY_CORRUPTION_DETECT_FLAG;
+ }
+#endif
+
+ if (i == pMemArray->nBlockCount - 1) {
+ *ptr = NULL; // End of list
+ } else {
+ // Points to the next block
+ *ptr = (void **)(((uint8_t *) ptr) + nBlockSize);
+ ptr += nBlockSize / sizeof(unsigned long);
+ }
+ }
+
+ NR5G_FAPI_MEMSET(alloc_track, sizeof(uint8_t) * ALLOC_TRACK_SIZE, 0,
+ sizeof(uint8_t) * ALLOC_TRACK_SIZE);
+
+ return SUCCESS;
+}
+
+//-------------------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] pWls Pointer to the nr5g_fapi_wls_ctx structure
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description
+ * This function created a partition and blocks of WLS memory for API exchange between FAPI and PHY
+ *
+**/
+//-------------------------------------------------------------------------------------------
+int wls_fapi_create_partition(
+ p_nr5g_fapi_wls_context_t pWls)
+{
+#define WLS_HUGE_DEF_PAGE_SIZEA 0x40000000LL
+ static long hugePageSize = WLS_HUGE_DEF_PAGE_SIZEA;
+ // NR5G_FAPI_MEMSET(pWls->pWlsMemBase , 0xCC, pWls->nTotalMemorySize); // This is done by the Master Only
+ pWls->pPartitionMemBase =
+ (void *)(((uint8_t *) pWls->pWlsMemBase) + hugePageSize);
+ pWls->nPartitionMemSize = (pWls->nTotalMemorySize - hugePageSize);
+
+ pWls->nTotalBlocks = pWls->nPartitionMemSize / MSG_MAXSIZE;
+ return wls_fapi_create_mem_array(&pWls->sWlsStruct, pWls->pPartitionMemBase,
+ pWls->nPartitionMemSize, MSG_MAXSIZE);
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] A pointer to the FAPI Memory Structure (Initialized by L2)
+ * @param[out] ppBlock Pointer where the allocated memory block is stored
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description This function allocates a memory block from the pool
+ *
+**/
+//------------------------------------------------------------------------------
+uint32_t wls_fapi_alloc_mem_array(
+ PWLS_FAPI_MEM_STRUCT pMemArray,
+ void **ppBlock)
+{
+ int idx;
+
+ if (pMemArray->ppFreeBlock == NULL) {
+ printf("wls_fapi_alloc_mem_array pMemArray->ppFreeBlock = NULL\n");
+ return FAILURE;
+ }
+ // FIXME: Remove after debugging
+ if (((void *)pMemArray->ppFreeBlock < pMemArray->pStorage) ||
+ ((void *)pMemArray->ppFreeBlock >= pMemArray->pEndOfStorage)) {
+ printf
+ ("wls_fapi_alloc_mem_array ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock);
+ return FAILURE;
+ }
+
+ pMemArray->ppFreeBlock =
+ (void **)((unsigned long)pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
+ *pMemArray->ppFreeBlock =
+ (void **)((unsigned long)*pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
+
+ if ((*pMemArray->ppFreeBlock != NULL) &&
+ (((*pMemArray->ppFreeBlock) < pMemArray->pStorage) ||
+ ((*pMemArray->ppFreeBlock) >= pMemArray->pEndOfStorage))) {
+ fprintf(stderr,
+ "ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
+ *pMemArray->ppFreeBlock);
+ return FAILURE;
+ }
+
+ *ppBlock = (void *)pMemArray->ppFreeBlock;
+ pMemArray->ppFreeBlock = (void **)(*pMemArray->ppFreeBlock);
+
+ idx =
+ (((uint64_t) * ppBlock -
+ (uint64_t) pMemArray->pStorage)) / pMemArray->nBlockSize;
+ if (alloc_track[idx]) {
+ printf
+ ("wls_fapi_alloc_mem_array Double alloc Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock,
+ *pMemArray->ppFreeBlock);
+ return FAILURE;
+ } else {
+#ifdef MEMORY_CORRUPTION_DETECT
+ uint32_t nBlockSize = pMemArray->nBlockSize, i;
+ uint8_t *p = (uint8_t *) * ppBlock;
+
+ p += (nBlockSize - 16);
+ for (i = 0; i < 16; i++) {
+ p[i] = MEMORY_CORRUPTION_DETECT_FLAG;
+ }
+#endif
+ alloc_track[idx] = 1;
+ }
+
+ //printf("Block allocd [%p,%p]\n", pMemArray, *ppBlock);
+
+ return SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] A pointer to the FAPI Memory Structure (Initialized by L2)
+ * @param[in] pBlock Pointer where the allocated memory block is stored
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description This function frees a WLS block of memory and adds
+ * it back to the pool
+ *
+**/
+//------------------------------------------------------------------------------
+uint32_t wls_fapi_free_mem_array(
+ PWLS_FAPI_MEM_STRUCT pMemArray,
+ void *pBlock)
+{
+ int idx;
+ unsigned long mask = (((unsigned long)pMemArray->nBlockSize) - 1);
+
+ pBlock = (void *)((unsigned long)pBlock & ~mask);
+
+ if ((pBlock < pMemArray->pStorage) || (pBlock >= pMemArray->pEndOfStorage)) {
+ printf
+ ("wls_fapi_free_mem_array WARNING: Trying to free foreign block;Arr=%p,Blk=%p pStorage [%p .. %p]\n",
+ pMemArray, pBlock, pMemArray->pStorage, pMemArray->pEndOfStorage);
+ return FAILURE;
+ }
+
+ idx =
+ (int)(((uint64_t) pBlock -
+ (uint64_t) pMemArray->pStorage)) / pMemArray->nBlockSize;
+
+ if (alloc_track[idx] == 0) {
+ printf
+ ("wls_fapi_free_mem_array ERROR: Double free Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock, pBlock);
+ return SUCCESS;
+ } else {
+#ifdef MEMORY_CORRUPTION_DETECT
+ uint32_t nBlockSize = pMemArray->nBlockSize, i;
+ uint8_t *p = (uint8_t *) pBlock;
+
+ p += (nBlockSize - 16);
+ for (i = 0; i < 16; i++) {
+ if (p[i] != MEMORY_CORRUPTION_DETECT_FLAG) {
+ printf("ERROR: Corruption\n");
+ nr5g_fapi_wls_print_stats();
+ exit(-1);
+ }
+ }
+#endif
+ alloc_track[idx] = 0;
+ }
+
+ if (((void *)pMemArray->ppFreeBlock) == pBlock) {
+ // Simple protection against freeing of already freed block
+ return SUCCESS;
+ }
+ // FIXME: Remove after debugging
+ if ((pMemArray->ppFreeBlock != NULL)
+ && (((void *)pMemArray->ppFreeBlock < pMemArray->pStorage)
+ || ((void *)pMemArray->ppFreeBlock >= pMemArray->pEndOfStorage))) {
+ printf
+ ("wls_fapi_free_mem_array ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
+ pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock);
+ return FAILURE;
+ }
+ // FIXME: Remove after debugging
+ if ((pBlock < pMemArray->pStorage) || (pBlock >= pMemArray->pEndOfStorage)) {
+ printf("wls_fapi_free_mem_array ERROR: Invalid block;Arr=%p,Blk=%p\n",
+ pMemArray, pBlock);
+ return FAILURE;
+ }
+
+ *((void **)pBlock) =
+ (void **)((unsigned long)pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0);
+ pMemArray->ppFreeBlock =
+ (void **)((unsigned long)pBlock & 0xFFFFFFFFFFFFFFF0);
+
+ //printf("Block freed [%p,%p]\n", pMemArray, pBlock);
+
+ return SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param size (if 0 fixed size from pool)
+ * @param Number of locations
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description This function initializes WLS layer primitives and allocates
+ * memory needed to exchange APIs between FAPI and PHY.
+**/
+//------------------------------------------------------------------------------
+void *wls_fapi_alloc_buffer(
+ uint32_t size,
+ uint32_t loc)
+{
+ void *pBlock = NULL;
+ p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
+
+ if (pthread_mutex_lock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
+ NR5G_FAPI_LOG(ERROR_LOG, ("unable to get lock alloc pthread mutex"));
+ exit(-1);
+ }
+
+ if (wls_fapi_alloc_mem_array(&pWls->sWlsStruct, &pBlock) != SUCCESS) {
+ printf("wls_fapi_alloc_buffer alloc error size[%d] loc[%d]\n", size,
+ loc);
+ nr5g_fapi_wls_print_stats();
+ exit(-1);
+ } else {
+ pWls->nAllocBlocks++;
+ }
+
+ //printf("----------------wls_fapi_alloc_buffer: size[%d] loc[%d] buf[%p] nAllocBlocks[%d]\n", size, loc, pBlock, pWls->nAllocBlocks);
+
+ //printf("[%p]\n", pBlock);
+
+ pWls->nTotalAllocCnt++;
+ if (loc < MAX_DL_BUF_LOCATIONS)
+ pWls->nTotalDlBufAllocCnt[loc]++;
+ else if (loc < MAX_UL_BUF_LOCATIONS)
+ pWls->nTotalUlBufAllocCnt++;
+
+ if (pthread_mutex_unlock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
+ NR5G_FAPI_LOG(ERROR_LOG, ("unable to unlock alloc pthread mutex"));
+ exit(-1);
+ }
+
+ return pBlock;
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] *pMsg Pointer to free
+ *
+ * @return void
+ *
+ * @descriptioni This function frees a block of memory and adds it back to
+ * the pool.
+ *
+**/
+//------------------------------------------------------------------------------
+void wls_fapi_free_buffer(
+ void *pMsg,
+ uint32_t loc)
+{
+ p_nr5g_fapi_wls_context_t pWls = nr5g_fapi_wls_context();
+
+ if (pthread_mutex_lock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
+ NR5G_FAPI_LOG(ERROR_LOG, ("unable to lock alloc pthread mutex"));
+ exit(-1);
+ }
+ //printf("----------------wls_fapi_free_buffer: buf[%p] loc[%d]\n", pMsg, loc);
+ if (wls_fapi_free_mem_array(&pWls->sWlsStruct, (void *)pMsg) == SUCCESS) {
+ pWls->nAllocBlocks--;
+ } else {
+ printf("wls_fapi_free_buffer Free error\n");
+ nr5g_fapi_wls_print_stats();
+ exit(-1);
+ }
+
+ pWls->nTotalFreeCnt++;
+ if (loc < MAX_DL_BUF_LOCATIONS)
+ pWls->nTotalDlBufFreeCnt[loc]++;
+ else if (loc < MAX_UL_BUF_LOCATIONS)
+ pWls->nTotalUlBufFreeCnt++;
+
+ if (pthread_mutex_unlock((pthread_mutex_t *) & pWls->fapi2phy_lock_alloc)) {
+ NR5G_FAPI_LOG(ERROR_LOG, ("unable to unlock alloc pthread mutex"));
+ exit(-1);
+ }
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param A pointer to a wls instance
+ *
+ * @return 0 if SUCCESS
+ *
+ * @description This function initializes the WLS layer FAPI2PHY interface
+ * primitives and allocates memory needed to exchange APIs
+ * between FAPI and PHY.
+**/
+//------------------------------------------------------------------------------
+uint8_t nr5g_fapi2Phy_wls_init(
+ p_nr5g_fapi_wls_context_t pwls)
+{
+ int nBlocks = 0;
+ uint8_t retval = SUCCESS;
+
+ retval = wls_fapi_create_partition(pwls);
+ if ((nBlocks = wls_fapi_add_blocks_to_ul()) == 0) {
+ return FAILURE;
+ }
+
+ return retval;
+}
+
+uint8_t get_stats_location(
+ uint8_t msg_type)
+{
+ uint8_t loc;
+ switch (msg_type) {
+ case MSG_TYPE_PHY_CONFIG_REQ:
+ loc = MEM_STAT_CONFIG_REQ;
+ break;
+ case MSG_TYPE_PHY_START_REQ:
+ loc = MEM_STAT_START_REQ;
+ break;
+ case MSG_TYPE_PHY_STOP_REQ:
+ loc = MEM_STAT_STOP_REQ;
+ break;
+ case MSG_TYPE_PHY_SHUTDOWN_REQ:
+ loc = MEM_STAT_SHUTDOWN_REQ;
+ break;
+ case MSG_TYPE_PHY_DL_CONFIG_REQ:
+ loc = MEM_STAT_DL_CONFIG_REQ;
+ break;
+ case MSG_TYPE_PHY_UL_CONFIG_REQ:
+ loc = MEM_STAT_UL_CONFIG_REQ;
+ break;
+ case MSG_TYPE_PHY_UL_DCI_REQ:
+ loc = MEM_STAT_UL_DCI_REQ;
+ break;
+ case MSG_TYPE_PHY_TX_REQ:
+ loc = MEM_STAT_TX_REQ;
+ break;
+ case MSG_TYPE_PHY_DL_IQ_SAMPLES:
+ loc = MEM_STAT_DL_IQ_SAMPLES;
+ break;
+ case MSG_TYPE_PHY_UL_IQ_SAMPLES:
+ loc = MEM_STAT_UL_IQ_SAMPLES;
+ break;
+ default:
+ loc = MEM_STAT_DEFAULT;
+ }
+
+ return loc;
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] pListElem Pointer to List element header
+ * @param[in] idx Subframe Number
+ *
+ * @return Number of blocks freed
+ *
+ * @description This function Frees all the blocks in a List Element Linked
+ * List coming from L1 by storing them into an array to be
+ * freed at a later point in time.
+**/
+//------------------------------------------------------------------------------
+void wls_fapi_add_recv_apis_to_free(
+ PMAC2PHY_QUEUE_EL pListElem,
+ uint32_t idx)
+{
+ PMAC2PHY_QUEUE_EL pNextMsg = NULL;
+ L1L2MessageHdr *p_msg_header = NULL;
+ PRXULSCHIndicationStruct p_phy_rx_ulsch_ind = NULL;
+ int count, i;
+ uint8_t *ptr = NULL;
+
+ WLS_HANDLE h_wls;
+ p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
+ h_wls = p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST];
+
+ count = g_to_free_recv_list_cnt[idx];
+ pNextMsg = pListElem;
+ while (pNextMsg) {
+ if (count >= TOTAL_FREE_BLOCKS) {
+ NR5G_FAPI_LOG(ERROR_LOG, ("%s: Reached max capacity of free list.\n"
+ "\t\t\t\tlist index: %d list count: %d max list count: %d",
+ __func__, idx, count, TOTAL_FREE_BLOCKS));
+ return;
+ }
+
+ g_to_free_recv_list[idx][count++] = (uint64_t) pNextMsg;
+ p_msg_header = (PL1L2MessageHdr) (pNextMsg + 1);
+ if (p_msg_header->nMessageType == MSG_TYPE_PHY_RX_ULSCH_IND) {
+ p_phy_rx_ulsch_ind = (PRXULSCHIndicationStruct) p_msg_header;
+ for (i = 0; i < p_phy_rx_ulsch_ind->nUlsch; i++) {
+ ptr = p_phy_rx_ulsch_ind->sULSCHPDUDataStruct[i].pPayload;
+ ptr = (uint8_t *) nr5g_fapi_wls_pa_to_va(h_wls, (uint64_t) ptr);
+
+ if (ptr) {
+ g_to_free_recv_list[idx][count++] = (uint64_t) ptr;
+ }
+ }
+ }
+ pNextMsg = pNextMsg->pNext;
+ }
+
+ g_to_free_recv_list[idx][count] = 0L;
+ g_to_free_recv_list_cnt[idx] = count;
+
+ NR5G_FAPI_LOG(DEBUG_LOG, ("To Free %d\n", count));
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] idx subframe Number
+ *
+ * @return Number of blocks freed
+ *
+ * @description This function frees all blocks that have been added to the
+ * free array
+**/
+//------------------------------------------------------------------------------
+void wls_fapi_free_recv_free_list(
+ uint32_t idx)
+{
+ PMAC2PHY_QUEUE_EL pNextMsg = NULL;
+ int count = 0;
+
+ if (idx >= TO_FREE_SIZE) {
+ NR5G_FAPI_LOG(ERROR_LOG, ("%s: list index: %d\n", __func__, idx));
+ return;
+ }
+
+ pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_recv_list[idx][count];
+ while (pNextMsg) {
+ wls_fapi_free_buffer(pNextMsg, MIN_UL_BUF_LOCATIONS);
+ g_to_free_recv_list[idx][count++] = 0L;
+ if (g_to_free_recv_list[idx][count])
+ pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_recv_list[idx][count];
+ else
+ pNextMsg = 0L;
+ }
+
+ NR5G_FAPI_LOG(DEBUG_LOG, ("Free %d\n", count));
+ g_to_free_recv_list_cnt[idx] = 0;
+
+ return;
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] pListElem Pointer to List element header
+ * @param[in] idx Subframe Number
+ *
+ * @return Number of blocks freed
+ *
+ * @description This function Frees all the blocks in a List Element Linked
+ * List coming from L1 by storing them into an array to be
+ * freed at a later point in time.
+**/
+//------------------------------------------------------------------------------
+void wls_fapi_add_send_apis_to_free(
+ PMAC2PHY_QUEUE_EL pListElem,
+ uint32_t idx)
+{
+ PMAC2PHY_QUEUE_EL pNextMsg = NULL;
+ L1L2MessageHdr *p_msg_header = NULL;
+ PRXULSCHIndicationStruct p_phy_rx_ulsch_ind = NULL;
+ int count, i;
+ uint8_t *ptr = NULL;
+
+ count = g_to_free_send_list_cnt[idx];
+ pNextMsg = pListElem;
+ while (pNextMsg) {
+ if (count >= TOTAL_FREE_BLOCKS) {
+ NR5G_FAPI_LOG(ERROR_LOG, ("%s: Reached max capacity of free list.\n"
+ "\t\t\t\tlist index: %d list count: %d max list count: %d",
+ __func__, idx, count, TOTAL_FREE_BLOCKS));
+ return;
+ }
+
+ g_to_free_send_list[idx][count++] = (uint64_t) pNextMsg;
+ p_msg_header = (PL1L2MessageHdr) (pNextMsg + 1);
+ if (p_msg_header->nMessageType == MSG_TYPE_PHY_RX_ULSCH_IND) {
+ p_phy_rx_ulsch_ind = (PRXULSCHIndicationStruct) p_msg_header;
+ for (i = 0; i < p_phy_rx_ulsch_ind->nUlsch; i++) {
+ ptr = p_phy_rx_ulsch_ind->sULSCHPDUDataStruct[i].pPayload;
+ if (ptr) {
+ g_to_free_send_list[idx][count++] = (uint64_t) ptr;
+ }
+ }
+ }
+ pNextMsg = pNextMsg->pNext;
+ }
+
+ g_to_free_send_list[idx][count] = 0L;
+ g_to_free_send_list_cnt[idx] = count;
+
+ NR5G_FAPI_LOG(DEBUG_LOG, ("To Free %d\n", count));
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] idx subframe Number
+ *
+ * @return Number of blocks freed
+ *
+ * @description This function frees all blocks that have been added to the
+ * free array
+**/
+//------------------------------------------------------------------------------
+void wls_fapi_free_send_free_list(
+ uint32_t idx)
+{
+ PMAC2PHY_QUEUE_EL pNextMsg = NULL;
+ L1L2MessageHdr *p_msg_header = NULL;
+ int count = 0, loc = 0;
+
+ if (idx >= TO_FREE_SIZE) {
+ NR5G_FAPI_LOG(ERROR_LOG, ("%s: list index: %d\n", __func__, idx));
+ return;
+ }
+
+ pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_send_list[idx][count];
+ while (pNextMsg) {
+ p_msg_header = (PL1L2MessageHdr) (pNextMsg + 1);
+ loc = get_stats_location(p_msg_header->nMessageType);
+ wls_fapi_free_buffer(pNextMsg, loc);
+ g_to_free_send_list[idx][count++] = 0L;
+ if (g_to_free_send_list[idx][count])
+ pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_send_list[idx][count];
+ else
+ pNextMsg = 0L;
+ }
+
+ NR5G_FAPI_LOG(DEBUG_LOG, ("Free %d\n", count));
+ g_to_free_send_list_cnt[idx] = 0;
+
+ return;
+}
+
+//------------------------------------------------------------------------------
+/** @ingroup nr5g_fapi_source_framework_wls_lib_group
+ *
+ * @param[in] idx subframe Number
+ *
+ * @return Number of blocks freed
+ *
+ * @description This function frees all blocks that have been added to the
+ * free array
+**/
+//------------------------------------------------------------------------------
+void wls_fapi_free_list_all(
+ void)
+{
+ uint32_t idx;
+
+ for (idx = 0; idx < TO_FREE_SIZE; idx++) {
+ wls_fapi_free_send_free_list(idx);
+ wls_fapi_free_recv_free_list(idx);
+ }
+
+ nr5g_fapi_wls_print_stats();
+}