X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?p=o-du%2Fphy.git;a=blobdiff_plain;f=wls_lib%2Ftest%2Fmac%2Fmac_wls.c;fp=wls_lib%2Ftest%2Fmac%2Fmac_wls.c;h=3f698848db4830f53e4204c7d2cff20b1c1f08b1;hp=0000000000000000000000000000000000000000;hb=9d66fca5c45c8b3e0d6eab6d51a90c8e9d2614dc;hpb=2fbf70096f64af622da983e88c5a64e90ad9bdbd diff --git a/wls_lib/test/mac/mac_wls.c b/wls_lib/test/mac/mac_wls.c new file mode 100644 index 0000000..3f69884 --- /dev/null +++ b/wls_lib/test/mac/mac_wls.c @@ -0,0 +1,1322 @@ +/****************************************************************************** +* +* 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. +* +*******************************************************************************/ + +/** + * @brief This file has Shared Memory interface functions between MAC and PHY + * @file testmac_wls.c + * @ingroup group_testmac + * @author Intel Corporation + **/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DPDK_WLS +#include "wls.h" +#include "wls_lib.h" +#include "mac_wls.h" +//#include "phy_printf.h" +//#include "aux_sys.h" +//#include "aux_timer.h" +//#include "mlog_lnx.h" + +//#include "nr5g_testmac_config_test.h" +//#include "nr5g_testmac_mac_phy_api_proc.h" + + +#define MSG_MAXSIZE ( 16384 * 16 ) + + +#define TO_FREE_SIZE ( 10 ) +#define TOTAL_FREE_BLOCKS ( 50 * 12) +#define ALLOC_TRACK_SIZE ( 16384 ) + +#define MEMORY_CORRUPTION_DETECT +#define MEMORY_CORRUPTION_DETECT_FLAG (0xAB) + +typedef struct wls_mac_mem_array +{ + void **ppFreeBlock; + void *pStorage; + void *pEndOfStorage; + uint32_t nBlockSize; + uint32_t nBlockCount; +} WLS_MAC_MEM_SRUCT, *PWLS_MAC_MEM_SRUCT; + +typedef struct wls_mac_ctx +{ + void *hWls; + void *pWlsMemBase; + WLS_MAC_MEM_SRUCT sWlsStruct; + + uint32_t nTotalMemorySize; + uint32_t nTotalBlocks; + uint32_t nAllocBlocks; + uint32_t nTotalAllocCnt; + uint32_t nTotalFreeCnt; + uint32_t nTotalUlBufAllocCnt; + uint32_t nTotalUlBufFreeCnt; + uint32_t nTotalDlBufAllocCnt; + uint32_t nTotalDlBufFreeCnt; +// Support for FAPI Translator + uint32_t nPartitionMemSize; + void *pPartitionMemBase; + + volatile pthread_mutex_t lock; + volatile pthread_mutex_t lock_alloc; +} WLS_MAC_CTX, *PWLS_MAC_CTX; + +static pthread_t *pwls_testmac_thread = NULL; +static WLS_MAC_CTX wls_mac_iface; +static int gwls_mac_ready = 0; +static pid_t gwls_pid = 0; +static uint32_t gToFreeListCnt[TO_FREE_SIZE] = {0}; +static uint64_t gpToFreeList[TO_FREE_SIZE][TOTAL_FREE_BLOCKS] = {{0L}}; +static uint8_t alloc_track[ALLOC_TRACK_SIZE]; +static uint64_t gTotalTick = 0, gUsedTick = 0; + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @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 wls_mac_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 group_testmac + * + * @param void + * + * @return Pointer to WLS_MAC_CTX stucture + * + * @description + * This function returns the WLS Local structure which has WLS related parameters + * +**/ +//------------------------------------------------------------------------------------------- +static PWLS_MAC_CTX wls_mac_get_ctx(void) +{ + return &wls_mac_iface; +} + +void wls_mac_print_stats(void) +{ + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + + printf("wls_mac_free_list_all:\n"); + printf(" nTotalBlocks[%d] nAllocBlocks[%d] nFreeBlocks[%d]\n", pWls->nTotalBlocks, pWls->nAllocBlocks, (pWls->nTotalBlocks- pWls->nAllocBlocks)); + printf(" nTotalAllocCnt[%d] nTotalFreeCnt[%d] Diff[%d]\n", pWls->nTotalAllocCnt, pWls->nTotalFreeCnt, (pWls->nTotalAllocCnt- pWls->nTotalFreeCnt)); + printf(" nDlBufAllocCnt[%d] nDlBufFreeCnt[%d] Diff[%d]\n", pWls->nTotalDlBufAllocCnt, pWls->nTotalDlBufFreeCnt, (pWls->nTotalDlBufAllocCnt- pWls->nTotalDlBufFreeCnt)); + printf(" nUlBufAllocCnt[%d] nUlBufFreeCnt[%d] Diff[%d]\n\n", pWls->nTotalUlBufAllocCnt, pWls->nTotalUlBufFreeCnt, (pWls->nTotalUlBufAllocCnt- pWls->nTotalUlBufFreeCnt)); +} + + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] ptr Address to convert + * + * @return Converted address + * + * @description + * This function converts Virtual Address to Physical Address + * +**/ +//------------------------------------------------------------------------------------------- +uint64_t wls_mac_va_to_pa(void *ptr) +{ + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + uint64_t ret = (uint64_t)WLS_VA2PA(pWls->hWls, ptr); + + //printf("wls_mac_va_to_pa: %p ->%p\n", ptr, (void*)ret); + + return ret; +} + + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] ptr Address to convert + * + * @return Converted address + * + * @description + * This function converts Physical Address to Virtual Address + * +**/ +//------------------------------------------------------------------------------------------- +void *wls_mac_pa_to_va(uint64_t ptr) +{ + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + void *ret = WLS_PA2VA(pWls->hWls, ptr); + + //printf("wls_mac_pa_to_va: %p -> %p\n", (void*)ptr, ret); + + return ret; +} + + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] pMemArray Pointer to WLS Memory management structure + * @param[in] pMemArrayMemory 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 partitioned by memory manager + * + * @return 0 if SUCCESS + * + * @description + * This function creates memory blocks from a flat buffer which will be used for communciation + * between MAC and PHY + * +**/ +//------------------------------------------------------------------------------------------- +uint32_t wls_mac_create_mem_array(PWLS_MAC_MEM_SRUCT pMemArray, + void *pMemArrayMemory, + uint32_t totalSize, uint32_t nBlockSize) +{ + int numBlocks = totalSize / nBlockSize; + void **ptr; + uint32_t i; + + printf("wls_mac_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); + } + } + + memset(alloc_track, 0, sizeof(uint8_t) * ALLOC_TRACK_SIZE); + + return SUCCESS; +} + + + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] pMemArray Pointer to WLS Memory management structure + * @param[out] ppBlock Pointer where allocated memory block is stored + * + * @return 0 if SUCCESS + * + * @description + * This function allocated a memory block from pool + * +**/ +//------------------------------------------------------------------------------------------- +uint32_t wls_mac_alloc_mem_array(PWLS_MAC_MEM_SRUCT pMemArray, void **ppBlock) +{ + int idx; + + if (pMemArray->ppFreeBlock == NULL) + { + printf("wls_mac_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_mac_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_mac_alloc_mem_array Double alloc Arr=%p,Stor=%p,Free=%p,Curr=%p\n", + pMemArray, pMemArray->pStorage, pMemArray->ppFreeBlock, + *pMemArray->ppFreeBlock); + } + 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 group_testmac + * + * @param[in] pMemArray Pointer to WLS Memory management structure + * @param[in] pBlock Pointer to block that needs to be added back to pool + * + * @return 0 if SUCCESS + * + * @description + * This function frees a WLS block of memory and adds it back to the pool + * +**/ +//------------------------------------------------------------------------------------------- +uint32_t wls_mac_free_mem_array(PWLS_MAC_MEM_SRUCT 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_mac_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_mac_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"); + wls_mac_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_mac_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_mac_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 group_testmac + * + * @param void + * + * @return Pointer to the memory block + * + * @description + * This function allocates a block of memory from the pool + * +**/ +//------------------------------------------------------------------------------------------- +void *wls_mac_alloc_buffer(uint32_t size, uint32_t loc) +{ + void *pBlock = NULL; + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + PWLS_MAC_MEM_SRUCT pMemArray = &pWls->sWlsStruct; + + pthread_mutex_lock((pthread_mutex_t *)&pWls->lock_alloc); + + if (wls_mac_alloc_mem_array(&pWls->sWlsStruct, &pBlock) != SUCCESS) + { + printf("wls_mac_alloc_buffer alloc error size[%d] loc[%d]\n", size, loc); + wls_mac_print_stats(); + exit(-1); + } + else + { + pWls->nAllocBlocks++; + } + + //printf("----------------wls_mac_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++; + else if (loc < MAX_UL_BUF_LOCATIONS) + pWls->nTotalUlBufAllocCnt++; + + pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock_alloc); + + return pBlock; +} + + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] *pMsg Pointer to free + * + * @return void + * + * @description + * This function frees a block of memory and adds it back to the pool + * +**/ +//------------------------------------------------------------------------------------------- +void wls_mac_free_buffer(void *pMsg, uint32_t loc) +{ + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + PWLS_MAC_MEM_SRUCT pMemArray = &pWls->sWlsStruct; + + pthread_mutex_lock((pthread_mutex_t *)&pWls->lock_alloc); + + //printf("----------------wls_mac_free_buffer: buf[%p] loc[%d]\n", pMsg, loc); + if (wls_mac_free_mem_array(&pWls->sWlsStruct, (void *)pMsg) == SUCCESS) + { + pWls->nAllocBlocks--; + } + else + { + printf("wls_mac_free_buffer Free error\n"); + wls_mac_print_stats(); + exit(-1); + } + + pWls->nTotalFreeCnt++; + if (loc < MAX_DL_BUF_LOCATIONS) + pWls->nTotalDlBufFreeCnt++; + else if (loc < MAX_UL_BUF_LOCATIONS) + pWls->nTotalUlBufFreeCnt++; + + pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock_alloc); +} + + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param void + * + * @return Number of free blocks + * + * @description + * This function queries the number of free blocks in the system + * +**/ +//------------------------------------------------------------------------------------------- +int wls_mac_num_free_blocks(void) +{ + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + + return (pWls->nTotalBlocks- pWls->nAllocBlocks); +} + + + +void wls_mac_free_list_all(void) +{ + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + uint32_t idx; + + for (idx = 0; idx < TO_FREE_SIZE; idx++) + { + wls_mac_free_list(idx); + } + + wls_mac_print_stats(); +} + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] pWls Pointer to the WLS_MAC_CTX structure + * + * @return 0 if SUCCESS + * + * @description + * This function created a partition and blocks of WLS memory for API exchange between MAC and PHY + * +**/ +//------------------------------------------------------------------------------------------- +int wls_mac_create_partition(PWLS_MAC_CTX pWls) +{ + memset(pWls->pWlsMemBase, 0xCC, pWls->nTotalMemorySize); + pWls->pPartitionMemBase = pWls->pWlsMemBase; + pWls->nPartitionMemSize = pWls->nTotalMemorySize/2; + pWls->nTotalBlocks = pWls->nTotalMemorySize / MSG_MAXSIZE; + return wls_mac_create_mem_array(&pWls->sWlsStruct, pWls->pPartitionMemBase, pWls->nPartitionMemSize, MSG_MAXSIZE); +} + + + +static volatile int gWlsMacPrintThreadInfo = 0; + +void wls_mac_print_thread_info(void) +{ + gWlsMacPrintThreadInfo = 1; + + return; +} + +void wls_mac_get_time_stats(uint64_t *pTotal, uint64_t *pUsed, uint32_t nClear) +{ + *pTotal = gTotalTick; + *pUsed = gUsedTick; + + if (nClear) + { + gTotalTick = 0; + gUsedTick = 0; + } +} + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] pMsgHeader Pointer to TxSdu Message Block + * @param[in] count Location in Free List Array + * @param[in] pToFreeList Array where all the blocks to free are stored + * + * @return New Location in free list array + * + * @description + * This function adds all the messages in a subframe coming from L1 to L2 to a free array to be + * freed back to the queue at a later point in time. + * +**/ +//------------------------------------------------------------------------------------------- +int wls_mac_sdu_zbc_block_add_to_free(void* pMsgHeaderHead, int count, uint64_t *pToFreeList) +{ + fapi_msg_t *p_fapi_msg = (fapi_msg_t *) pMsgHeaderHead; + + if (p_fapi_msg->msg_id == FAPI_TX_DATA_REQUEST) + { + fapi_tx_data_req_t *p_tx_data_req = (fapi_tx_data_req_t *) p_fapi_msg; + p_fapi_api_queue_elem_t p_list_elm = ((p_fapi_api_queue_elem_t) p_tx_data_req) - 1; + p_fapi_api_queue_elem_t p_sdu_elm = p_list_elm->p_tx_data_elm_list; + while(p_sdu_elm) + { + if (count < TOTAL_FREE_BLOCKS) + { + pToFreeList[count++] = (uint64_t) p_sdu_elm; + } + else + { + printf("wls_mac_sdu_zbc_block_add_to_free: ERROR: Reached max Number of Free Blocks\n"); + return count; + } + p_sdu_elm = p_sdu_elm->p_next; + } + } + + return count; +} + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @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. + * +**/ +//------------------------------------------------------------------------------------------- +int wls_mac_add_to_free(p_fapi_api_queue_elem_t pListElem, uint32_t idx) +{ + p_fapi_api_queue_elem_t pNextMsg = NULL; + void* pMsgHeader; + int count = gToFreeListCnt[idx], nZbcBlocks; + + pNextMsg = pListElem; + + while (pNextMsg) + { + if (count < TOTAL_FREE_BLOCKS) + { + gpToFreeList[idx][count] = (uint64_t)pNextMsg; + } + else + { + printf("wls_mac_add_to_free: ERROR: Reached max Number of Free Blocks\n"); + return count; + } + + if (pNextMsg->msg_type != FAPI_MSG_HEADER_IND) + { + pMsgHeader = (void *) (pNextMsg + 1); + count++; + count = wls_mac_sdu_zbc_block_add_to_free(pMsgHeader, count, gpToFreeList[idx]); + } + + if (pNextMsg->p_next) + { + pNextMsg = (p_fapi_api_queue_elem_t)(pNextMsg->p_next); + } + else + { + pNextMsg = 0; + } + } + + gpToFreeList[idx][count] = 0L; + gToFreeListCnt[idx] = count; + + printf("To Free %d\n", count); + + return count; +} + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] idx subframe Number + * + * @return Number of blocks freed + * + * @description + * This function frees all blocks that have been added to the free array + * +**/ +//------------------------------------------------------------------------------------------- +int wls_mac_free_list(uint32_t idx) +{ + p_fapi_api_queue_elem_t pNextMsg = NULL; + int count = 0; + + if(idx >= TO_FREE_SIZE){ + printf("Error idx %d\n", idx); + return 0; + } + + pNextMsg = (p_fapi_api_queue_elem_t)gpToFreeList[idx][count]; + + while (pNextMsg) + { + wls_mac_free_buffer(pNextMsg, MIN_DL_BUF_LOCATIONS+0); + gpToFreeList[idx][count] = (uint64_t) NULL; + count++; + if (gpToFreeList[idx][count]) + pNextMsg = (p_fapi_api_queue_elem_t)gpToFreeList[idx][count]; + else + pNextMsg = 0; + } + + printf("Free %d\n", count); + gToFreeListCnt[idx] = 0; + + return count; +} + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param void + * + * @return 0 if SUCCESS + * + * @description + * This function is called at WLS init and waits in an infinite for L1 to respond back with some information + * needed by the L2 + * +**/ +//------------------------------------------------------------------------------------------- +int wls_mac_ready(void) +{ + int ret = 0; + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + ret = WLS_Ready(pWls->hWls); + + return ret; +} + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param void + * + * @return Number of blocks of APIs received + * + * @description + * This functions waits in a infinite loop for L1 to send a list of APIs to MAC. This is called + * during runtime when L2 sends a API to L1 and then waits for response back. + * +**/ +//------------------------------------------------------------------------------------------- +int wls_mac_wait(void) +{ + int ret = 0; + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + + ret = WLS_Wait(pWls->hWls); + + return ret; +} + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[out] data Location where First API from L1 is stored + * + * @return Size of Message sent from L1 + * + * @description + * This function queries the APIs sent from L1 to L2 and gets the first pointer to the linked list + * +**/ +//------------------------------------------------------------------------------------------- +uint32_t wls_mac_recv(uint64_t *data, uint16_t *nFlags) +{ + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + uint32_t msgSize = 0; + uint16_t msgType = 0; + + *data = WLS_Get(pWls->hWls, &msgSize, &msgType, nFlags); + + return msgSize; +} + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] pMsg Pointer to API block that needs to be sent to L1 + * @param[in] MsgSize Size of Message + * @param[in] MsgTypeID Message Id + * @param[in] Flags Special Flags needed for WLS + * + * @return 0 if SUCCESS + * + * @description + * This function adds a block of API from L2 to L1 which will be sent later + * +**/ +//------------------------------------------------------------------------------------------- +int wls_mac_put(uint64_t pMsg, uint32_t MsgSize, uint16_t MsgTypeID, uint16_t Flags) +{ + int ret = 0; + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + + //printf("wls_mac_put: %p size: %d type: %d nFlags: %d\n", (void*)pMsg, MsgSize, MsgTypeID, Flags); + // wls_mac_show_data((void*)wls_alloc_buffer(pMsg), MsgSize); + ret = WLS_Put(pWls->hWls, pMsg, MsgSize, MsgTypeID, Flags); + + return ret; +} + + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] pMsgHeader Pointer to the TxSduReq Message block + * @param[in] nFlags Special nFlags needed for WLS + * @param[in] nZbcBlocks Number of ZBC blocks in list + * + * @return 0 if SUCCESS + * + * @description + * This function adds all the ZBC blocks in a TXSDU Message and prepares them to be sent to the L1 + * +**/ +//------------------------------------------------------------------------------------------- +uint32_t wls_mac_send_zbc_blocks(void *pMsgHeaderHead, uint16_t nFlags, int *nZbcBlocks, uint32_t nFlagsUrllc) +{ + fapi_tx_data_req_t *p_tx_data_req = (fapi_tx_data_req_t *) pMsgHeaderHead; + p_fapi_api_queue_elem_t p_list_elm = ((p_fapi_api_queue_elem_t) p_tx_data_req) - 1; + p_list_elm = p_list_elm->p_tx_data_elm_list; + + int ret = 0; + uint8_t nMsgType; + uint32_t isLast, nPduLen; + uint16_t list_flags = nFlags; + void *pPayload = NULL; + + printf("wls_mac_put ZBC blocks: %d\n", nFlags); + + while (p_list_elm) + { + nPduLen = p_list_elm->msg_len + sizeof(fapi_api_queue_elem_t); + pPayload = (void *) p_list_elm; + nMsgType = FAPI_MSG_PHY_ZBC_BLOCK_REQ; + + if (p_list_elm->p_next) + isLast = 0; + else + isLast = 1; + + if ((list_flags & WLS_TF_FIN) && isLast) + nFlags = WLS_SG_LAST; // TXSDU.req was last block in the list hence ZBC block is last + else + nFlags = WLS_SG_NEXT; // more blocks in the list + + printf("wls_mac_put 0x%016lx msg type: %x nFlags %x\n", (uint64_t) pPayload, nMsgType, nFlags); + ret = wls_mac_put((uint64_t) pPayload, nPduLen, nMsgType, nFlags); + if (ret != 0) + { + printf("Error ZBC block 0x%016lx\n", (uint64_t) pPayload); + return FAILURE; + } + p_list_elm = p_list_elm->p_next; + } + + return SUCCESS; +} + + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] pMsgHeader Pointer to the TxSDuReq Message block + * @param[out] nZbcBlocks Number of ZBC blocks + * + * @return 1 if this block is a TxSduReq message. 0 else. + * + * @description + * This function checks if a block is a TxSduReq messages and counts the number of ZBC blocks in this + * API + * +**/ +//------------------------------------------------------------------------------------------- +int wls_mac_is_sdu_zbc_block(void* pMsgHeaderHead, int *nZbcBlocks) +{ + fapi_tx_data_req_t *p_tx_data_req = (fapi_tx_data_req_t *) pMsgHeaderHead; + p_fapi_api_queue_elem_t p_list_elm = + ((p_fapi_api_queue_elem_t) p_tx_data_req) - 1; + *nZbcBlocks = 0; + + if (p_tx_data_req->header.msg_id == FAPI_TX_DATA_REQUEST && + p_list_elm->p_tx_data_elm_list) + { + return 1; + } + + return 0; +} + + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] data Pointer to the Linked list header + * + * @return 0 if SUCCESS + * + * @description + * This function sends a list of APIs to the L1 + * +**/ +//------------------------------------------------------------------------------------------- +uint32_t wls_mac_send_msg_to_phy(void *data) +{ + uint32_t ret = SUCCESS; + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + PWLS_MAC_MEM_SRUCT pMemArray = &pWls->sWlsStruct; + p_fapi_api_queue_elem_t pCurrMsg = NULL; + p_fapi_api_queue_elem_t pListElem = NULL; + static uint32_t idx = 0; + + fapi_msg_t *pMsgHeader; + uint16_t nFlags; + int nZbcBlocks = 0, isZbc = 0, count = 0; + + printf("wls_mac_send_msg_to_phy\n"); + printf("data (0x%lX) sending to phy...\n", (unsigned long)data); + + pthread_mutex_lock((pthread_mutex_t *)&pWls->lock); + + if (gwls_mac_ready) + { + pListElem = (p_fapi_api_queue_elem_t)data; + wls_mac_add_to_free(pListElem, idx); + count++; + + + ret = wls_mac_put(wls_mac_va_to_pa(pListElem), + pListElem->msg_len + sizeof(fapi_api_queue_elem_t), + pMsgHeader->msg_id, nFlags); + if (ret != 0) + { + printf("Error\n"); + pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock); + return FAILURE; + } + } + + pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock); + return ret; +} + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @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 + * +**/ +//------------------------------------------------------------------------------------------- +int wls_mac_add_blocks_to_ul(void) +{ + int ret = 0; + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + + void *pMsg = wls_mac_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+0); + + if(pMsg) + { + /* allocate blocks for UL transmittion */ + while(WLS_EnqueueBlock(pWls->hWls,(uint64_t)wls_mac_va_to_pa(pMsg))) + { + ret++; + pMsg = wls_mac_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+1); + if(WLS_EnqueueBlock(pWls->hWls,(uint64_t)wls_mac_va_to_pa(pMsg))) + { + ret++; + pMsg = wls_mac_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+1); + } + + if(!pMsg) + break; + } + + // free not enqueued block + if(pMsg) + { + wls_mac_free_buffer(pMsg, MIN_UL_BUF_LOCATIONS+3); + } + } + + return ret; +} + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] data Thread Local Context Structure Pointer + * + * @return NULL + * + * @description + * This is the WLS Receiver thread that is created at Testmac Init and is responsible for receiving + * APIs from L1 to MAC + * +**/ +//------------------------------------------------------------------------------------------- +void *wls_mac_rx_task() +{ + void* buffer_va = 0; + uint64_t buffer_pa = 0; + uint32_t get,i, rc = 0; + + uint32_t size = 0; + uint64_t tWake = 0, tWakePrev = 0, tSleep = 0; + uint16_t nFlags; + p_fapi_api_queue_elem_t pElm = NULL; + p_fapi_api_queue_elem_t pFirst = NULL; + p_fapi_api_queue_elem_t pPrev = NULL; + + + usleep(1000); + + wls_mac_ready(); + + while (1) + { + get = wls_mac_wait(); + + if (get == 0) + { + continue; + } + printf("Got %d messages from FAPI Translator\n", get); + while(get--) + { + size = wls_mac_recv((uint64_t *)&buffer_pa, &nFlags); + buffer_va = wls_mac_pa_to_va(buffer_pa); + pElm = (p_fapi_api_queue_elem_t) buffer_va; + + + if (pFirst == NULL) + pFirst = pElm; + + if (nFlags != WLS_TF_FIN) + { + wls_mac_print_recv_list((p_fapi_api_queue_elem_t) pElm, i); + i++; + } + if(pPrev) + pPrev->p_next = pElm; + + pPrev = pElm; + + if ((nFlags & WLS_TF_FIN)) + { + // send to MAC + if (pPrev) + { + pPrev->p_next = NULL; + } + + wls_mac_print_recv_list((p_fapi_api_queue_elem_t) pFirst, i); + + pFirst= NULL; + pPrev = NULL; + return NULL; + } + else + { + } + } + wls_mac_add_blocks_to_ul(); + + } + + return NULL; +} + +void wls_mac_print_recv_list(p_fapi_api_queue_elem_t list, uint32_t i) +{ + printf("\nMAC received response %d from FAPI\n",i); +} + +p_fapi_api_queue_elem_t wls_mac_create_elem(uint16_t num_msg, uint32_t align_offset, uint32_t msg_type, uint32_t n_loc) +{ + p_fapi_api_queue_elem_t p_list_elem; + + p_list_elem = (p_fapi_api_queue_elem_t)wls_mac_alloc_buffer(num_msg * align_offset + sizeof(fapi_api_queue_elem_t), n_loc); + + //Fill header for link list of API messages + if (p_list_elem) + { + p_list_elem->msg_type = (uint8_t)msg_type; + p_list_elem->num_message_in_block = 1; + p_list_elem->align_offset = (uint16_t)align_offset; + p_list_elem->msg_len = num_msg * align_offset; + p_list_elem->p_next = NULL; + } + + return p_list_elem; +} + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param void + * + * @return 0 if SUCCESS + * + * @description + * This function initialized the WLS threads for the Testmac and allocates memory needed to + * exchange APIs between MAC and PHY + * +**/ +//------------------------------------------------------------------------------------------- +uint32_t wls_mac_init(char * wls_device_name, uint64_t nTotalMemorySize) +{ + uint32_t ret = FAILURE; + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + uint8_t *pMemZone; + static const struct rte_memzone *mng_memzone; + wls_drv_ctx_t *pDrv_ctx; + + sleep(1); + + pthread_mutex_init((pthread_mutex_t *)&pWls->lock, NULL); + pthread_mutex_init((pthread_mutex_t *)&pWls->lock_alloc, NULL); + + pWls->nTotalAllocCnt = 0; + pWls->nTotalFreeCnt = 0; + pWls->nTotalUlBufAllocCnt = 0; + pWls->nTotalUlBufFreeCnt = 0; + pWls->nTotalDlBufAllocCnt = 0; + pWls->nTotalDlBufFreeCnt = 0; + + pWls->hWls = WLS_Open(wls_device_name, WLS_MASTER_CLIENT, nTotalMemorySize); + if (pWls->hWls) + { + /* allocate chuck of memory */ + pWls->pWlsMemBase = WLS_Alloc(pWls->hWls, nTotalMemorySize); + if (pWls->pWlsMemBase) + { + pWls->nTotalMemorySize = (uint32_t) nTotalMemorySize; + + ret = wls_mac_create_partition(pWls); + + if (ret == SUCCESS) + { + int nBlocks = 0; + gwls_mac_ready = 1; + + nBlocks = WLS_EnqueueBlock(pWls->hWls, wls_mac_va_to_pa(wls_mac_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+2))); + /* allocate blocks for UL transmition */ + while(WLS_EnqueueBlock(pWls->hWls, wls_mac_va_to_pa(wls_mac_alloc_buffer(0, MIN_UL_BUF_LOCATIONS+3)))) + { + nBlocks++; + } + + printf("WLS inited ok [%d]\n\n", nBlocks); + } + else + { + printf("can't create WLS Partition"); + return FAILURE; + } + + } + else + { + printf("can't allocate WLS memory"); + return FAILURE; + } + } + else + { + printf("can't open WLS instance"); + return FAILURE; + } + + return SUCCESS; +} + + +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param void + * + * @return 0 if SUCCESS + * + * @description + * This function destroys the WLS layer for the testmac and de-allocates any memory used + * +**/ +//------------------------------------------------------------------------------------------- +uint32_t wls_mac_destroy(void) +{ + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + + if (pwls_testmac_thread) + { + pthread_cancel(*pwls_testmac_thread); + + free(pwls_testmac_thread); + pwls_testmac_thread = NULL; + + if(pWls->pWlsMemBase) + { + WLS_Free(pWls->hWls, pWls->pWlsMemBase); + } + + WLS_Close(pWls->hWls); + printf("wls_mac_rx_task: [PID: %6d]... Stopping\n", gwls_pid); + } + + return SUCCESS; +} + +uint8_t mac_dpdk_init() +{ + uint8_t retval; + char whitelist[32]; + uint8_t i; + + char *argv[] = {"mac_app", "--proc-type=secondary", + "--file-prefix", "wls", whitelist}; + + int argc = RTE_DIM(argv); + + /* initialize EAL first */ + sprintf(whitelist, "-w %s", "0000:00:06.0"); + printf("[MAC] Calling rte_eal_init: "); + + for (i = 0; i < RTE_DIM(argv); i++) + { + printf("%s ", argv[i]); + } + printf("\n"); + + if (rte_eal_init(argc, argv) < 0) + rte_panic("Cannot init EAL\n"); + + return SUCCESS; +}