/****************************************************************************** * * 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. * *******************************************************************************/ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "config.h" #ifndef MLOG_ENABLED #include "../../lib/src/mlog_lnx_xRAN.h" #else #include "mlog_lnx.h" #endif #include "xran_fh_lls_cu.h" //#include "xran_pkt.h" //#include "xran_up_api.h" #include "xran_cp_api.h" #include "xran_sync_api.h" #include "xran_mlog_task_id.h" #define SW_FPGA_TOTAL_BUFFER_LEN 4*1024*1024*1024 #define SW_FPGA_SEGMENT_BUFFER_LEN 1*1024*1024*1024 #define SW_FPGA_FH_TOTAL_BUFFER_LEN 1*1024*1024*1024 #define FPGA_TO_SW_PRACH_RX_BUFFER_LEN (8192) #define NSEC_PER_SEC 1000000000 #define MAX_PKT_BURST (448+4) // 4x14x8 #define N_MAX_BUFFER_SEGMENT MAX_PKT_BURST #define MAIN_PRIORITY 98 #define NUM_OF_SUBFRAME_PER_FRAME (10) enum app_state state; uint64_t tick_per_usec; static volatile uint64_t timer_last_irq_tick = 0; static uint64_t tsc_resolution_hz = 0; RuntimeConfig startupConfiguration = {0}; //FH FPGA buffer uint32_t nFpgaToSW_FTH_RxBufferLen; uint32_t nFpgaToSW_PRACH_RxBufferLen; uint32_t nSW_ToFpga_FTH_TxBufferLen; static XRANFHINIT xranInit; void * xranHandle = NULL; XRANFHCONFIG xranConf; PXRANFHCONFIG pXranConf = NULL; typedef struct { uint32_t phaseFlag :1; uint32_t NRARFCN :22; uint32_t SULFreShift :1; uint32_t SULFlag :1; uint32_t rsv :7; }FPGAPhaseCompCfg; typedef struct XranLibConfig { uint32_t nDriverCoreId; uint32_t nTimingAdvance; uint32_t nFhConfig; uint32_t nFhBufIntFlag; uint32_t nSectorNum; uint32_t nNrOfSlotInSf; uint32_t nNrofSfInFrame; void * pFthInstanceHandles; }XranLibConfigStruct; typedef enum { XRANFTHTX_OUT = 0, XRANFTHRX_IN, XRANFTHRACH_IN, MAX_SW_XRAN_INTERFACE_NUM }SWXRANInterfaceTypeEnum; /* * manage one cell's all Ethernet frames for one DL or UL LTE subframe */ typedef struct { /* -1-this subframe is not used in current frame format 0-this subframe can be transmitted, i.e., data is ready 1-this subframe is waiting transmission, i.e., data is not ready 10 - DL transmission missing deadline. When FE needs this subframe data but bValid is still 1, set bValid to 10. */ int32_t bValid ; // when UL rx, it is subframe index. int32_t nSegToBeGen; int32_t nSegGenerated; // how many date segment are generated by DL LTE processing or received from FE // -1 means that DL packet to be transmitted is not ready in BS int32_t nSegTransferred; // number of data segments has been transmitted or received struct rte_mbuf *pData[N_MAX_BUFFER_SEGMENT]; // point to DPDK allocated memory pool XRANBufferListStruct sBufferList; } BbuIoBufCtrlStruct; typedef struct { uint64_t nCoreMask; int16_t cpuSocketId; uint8_t nDriverCoreId; uint8_t nFHCoreId; struct rte_mempool *bbuio_buf_pool; /* io struct */ BbuIoBufCtrlStruct sFrontHaulTxBbuIoBufCtrl[XRAN_N_FE_BUF_LEN][XRAN_MAX_SECTOR_NR][XRAN_MAX_ANTENNA_NR]; BbuIoBufCtrlStruct sFrontHaulRxBbuIoBufCtrl[XRAN_N_FE_BUF_LEN][XRAN_MAX_SECTOR_NR][XRAN_MAX_ANTENNA_NR]; BbuIoBufCtrlStruct sFHPrachRxBbuIoBufCtrl[XRAN_N_FE_BUF_LEN][XRAN_MAX_SECTOR_NR][XRAN_MAX_ANTENNA_NR]; /* buffers lists */ XRANFlatBufferStruct sFrontHaulTxBuffers[XRAN_N_FE_BUF_LEN][XRAN_MAX_SECTOR_NR][XRAN_MAX_ANTENNA_NR][XRAN_NUM_OF_SYMBOL_PER_SLOT]; XRANFlatBufferStruct sFrontHaulRxBuffers[XRAN_N_FE_BUF_LEN][XRAN_MAX_SECTOR_NR][XRAN_MAX_ANTENNA_NR][XRAN_NUM_OF_SYMBOL_PER_SLOT]; XRANFlatBufferStruct sFHPrachRxBuffers[XRAN_N_FE_BUF_LEN][XRAN_MAX_SECTOR_NR][XRAN_MAX_ANTENNA_NR][XRAN_NUM_OF_SYMBOL_PER_SLOT]; void* nInstanceHandle[XRAN_PORTS_NUM][XRAN_MAX_SECTOR_NR]; // instance per sector uint32_t nBufPoolIndex[XRAN_MAX_SECTOR_NR][MAX_SW_XRAN_INTERFACE_NUM]; // every api owns unique buffer pool uint16_t nInstanceNum; /*subframe type for this TTI: 0: DL control + DL data 1: DL control + DL data + UL control 2: DL control + UL data 3: DL control + UL data + UL control */ uint8_t nSubframeType; uint64_t nTscTiming[XRAN_N_FE_BUF_LEN]; // records the TSC when a timing packet is received. } BbuXranIoIfStruct; static BbuXranIoIfStruct gsXranIoIf; static XranLibConfigStruct *gpXranLibConfig = NULL; #define CPU_HZ tick_per_usec //us /* Application User space functions */ void xran_fh_rx_callback(void *pCallbackTag, int32_t status); void xran_fh_rx_prach_callback(void *pCallbackTag, int32_t status); static BbuXranIoIfStruct *xran_get_ctx(void) { return &gsXranIoIf; } static void print_menu() { puts("+---------------------------------------+"); puts("| Press 1 to start 5G NR XRAN traffic |"); puts("| Press 2 reserved for future use |"); puts("| Press 3 to quit |"); puts("+---------------------------------------+"); } void xran_fh_rx_callback(void *pCallbackTag, XranStatusInt32 status) { uint64_t t1 = MLogTick(); uint32_t mlogVar[10]; uint32_t mlogVarCnt = 0; mlogVar[mlogVarCnt++] = 0xCCCCCCCC; mlogVar[mlogVarCnt++] = status >> 16; /* tti */ mlogVar[mlogVarCnt++] = status & 0xFF; /* sym */ MLogAddVariables(mlogVarCnt, mlogVar, MLogTick()); rte_pause(); MLogTask(PID_GNB_SYM_CB, t1, MLogTick()); return; } void xran_fh_rx_prach_callback(void *pCallbackTag, XranStatusInt32 status) { uint64_t t1 = MLogTick(); rte_pause(); MLogTask(PID_GNB_PRACH_CB, t1, MLogTick()); } //------------------------------------------------------------------------------------------- /** @ingroup group_nbiot_source_auxlib_timer * * @param void * * @return Ticks * * @description * This function reads the rtdsc clock and returns the current value in there. * **/ //------------------------------------------------------------------------------------------- unsigned long timer_get_ticks(void) { unsigned long ret; union { unsigned long tsc_64; struct { uint32_t lo_32; uint32_t hi_32; }; } tsc; __asm volatile("rdtsc" : "=a" (tsc.lo_32), "=d" (tsc.hi_32)); ret = ((unsigned long)tsc.tsc_64); return ret; } //------------------------------------------------------------------------------------------- /** @ingroup group_lte_source_auxlib_timer * * @param void * * @return 0 if SUCCESS * * @description * This function gets the clock speed of the core and figures out number of ticks per usec. * It is used by l1app and testmac applications to initialize the mlog utility * **/ //------------------------------------------------------------------------------------------- int timer_set_tsc_freq_from_clock(void) { #define NS_PER_SEC 1E9 struct timespec sleeptime = {.tv_nsec = 5E8 }; /* 1/2 second */ struct timespec t_start, t_end; uint64_t tsc_resolution_hz = 0; if (clock_gettime(CLOCK_MONOTONIC_RAW, &t_start) == 0) { unsigned long ns, end, start = timer_get_ticks(); nanosleep(&sleeptime,NULL); clock_gettime(CLOCK_MONOTONIC_RAW, &t_end); end = timer_get_ticks(); ns = ((t_end.tv_sec - t_start.tv_sec) * NS_PER_SEC); ns += (t_end.tv_nsec - t_start.tv_nsec); double secs = (double)ns/NS_PER_SEC; tsc_resolution_hz = (unsigned long)((end - start)/secs); tick_per_usec = (tsc_resolution_hz / 1000000); printf("System clock (rdtsc) resolution %lu [Hz]\n", tsc_resolution_hz); printf("Ticks per us %lu\n", tick_per_usec); return 0; } return -1; } int physide_dl_tti_call_back(void * param) { uint64_t t1 = MLogTick(); rte_pause(); MLogTask(PID_GNB_PROC_TIMING, t1, MLogTick()); return 0; } int physide_ul_half_slot_call_back(void * param) { uint64_t t1 = MLogTick(); rte_pause(); MLogTask(PID_GNB_PROC_TIMING, t1, MLogTick()); return 0; } int physide_ul_full_slot_call_back(void * param) { uint64_t t1 = MLogTick(); rte_pause(); MLogTask(PID_GNB_PROC_TIMING, t1, MLogTick()); return 0; } int32_t init_xran(void) { BbuXranIoIfStruct *psBbuIo = xran_get_ctx(); XranStatusInt32 status; int32_t nSectorIndex[XRAN_MAX_SECTOR_NR]; int32_t nSectorNum; int32_t i, j, k, z; void *ptr; uint32_t *u32dptr; uint16_t *u16dptr; uint8_t *u8dptr; SWXRANInterfaceTypeEnum eInterfaceType; XranLibConfigStruct *ptrLibConfig; XRANBufferListStruct *pFthTxBuffer[XRAN_MAX_SECTOR_NR][XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; XRANBufferListStruct *pFthRxBuffer[XRAN_MAX_SECTOR_NR][XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; XRANBufferListStruct *pFthRxRachBuffer[XRAN_MAX_SECTOR_NR][XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; FPGAPhaseCompCfg *pPhaseCompDl = NULL; FPGAPhaseCompCfg *pPhaseCompUl = NULL; uint32_t nPhaseCompDl,nPhaseCompUl; #if 0 printf("init_xran: nFpgaProbe[%d] nSecNum[%d] nUENum[%d] nTimeAdvance[%d] nEthPorts[%d] nPhaseCompFlag[%d]\n", psFPGAInitPara->nFpgaProbe, psFPGAInitPara->nSecNum, psFPGAInitPara->nUENum, psFPGAInitPara->nTimeAdvance, psFPGAInitPara->nEthPorts, psFPGAInitPara->nPhaseCompFlag); for (i = 0; i < nSectorNum; i ++) { printf(" [%d]: nDlArfcn[%d] nUlArfcn[%d]\n", i, psFPGAInitPara->nDlArfcn[i], psFPGAInitPara->nUlArfcn[i]); } #endif for (nSectorNum = 0; nSectorNum < XRAN_MAX_SECTOR_NR; nSectorNum++) { nSectorIndex[nSectorNum] = nSectorNum; } nSectorNum = numCCPorts; printf ("XRAN front haul xran_mm_init \n"); status = xran_mm_init (xranHandle, (uint64_t) SW_FPGA_FH_TOTAL_BUFFER_LEN, SW_FPGA_SEGMENT_BUFFER_LEN); if (status != XRAN_STATUS_SUCCESS) { printf ("Failed at XRAN front haul xran_mm_init \n"); exit(-1); } psBbuIo->nInstanceNum = numCCPorts; for (k = 0; k < XRAN_PORTS_NUM; k++) { status = xran_sector_get_instances (xranHandle, psBbuIo->nInstanceNum,psBbuIo->nInstanceHandle[k]); if (status != XRAN_STATUS_SUCCESS) { printf ("get sector instance failed %d for XRAN nInstanceNum %d\n",k, psBbuIo->nInstanceNum); exit(-1); } } printf("Sucess xran_mm_init \n"); gpXranLibConfig = (XranLibConfigStruct*)malloc(sizeof(XranLibConfigStruct)); ptrLibConfig = gpXranLibConfig; if (ptrLibConfig) { #if 0 ptrLibConfig->nDriverCoreId = psBbuIo->nDriverCoreId; ptrLibConfig->pFecInstanceHandles = &(psBbuIo->nInstanceHandle[FPGA_FEC][0]); ptrLibConfig->pFthInstanceHandles = &(psBbuIo->nInstanceHandle[FPGA_FRONTHAUL][0]); ptrLibConfig->nTimingAdvance = psFPGAInitPara->nTimeAdvance; ptrLibConfig->nFhConfig = psFPGAInitPara->nEthPorts; ptrLibConfig->nFhBufIntFlag = 0; //need init fronthaul buffer, then set to 1. ptrLibConfig->nNrofSfInFrame = NUM_OF_SUBFRAME_PER_FRAME; ptrLibConfig->nNrOfSlotInSf = pConfigParams->nNumOfSlotPerSubframe; if (pConfigParams->nNumerology < 3) { ptrLibConfig->nSectorNum = psFPGAInitPara->nSecNum; } #endif } else { printf ("could not allocate ptrLibConfig in init_xran\n"); exit(-1); } printf("nSectorNum %d\n", nSectorNum); /* Init Memory */ for(i = 0; inBufPoolIndex[nSectorIndex[i]][eInterfaceType], XRAN_N_FE_BUF_LEN*XRAN_MAX_ANTENNA_NR*XRAN_NUM_OF_SYMBOL_PER_SLOT, nSW_ToFpga_FTH_TxBufferLen); if(XRAN_STATUS_SUCCESS != status) { printf("Failed at xran_bm_init , status %d\n", status); iAssert(status == XRAN_STATUS_SUCCESS); } for(j = 0; j < XRAN_N_FE_BUF_LEN; j++) { for(z = 0; z < XRAN_MAX_ANTENNA_NR; z++){ psBbuIo->sFrontHaulTxBbuIoBufCtrl[j][i][z].bValid = 0; psBbuIo->sFrontHaulTxBbuIoBufCtrl[j][i][z].nSegGenerated = -1; psBbuIo->sFrontHaulTxBbuIoBufCtrl[j][i][z].nSegToBeGen = -1; psBbuIo->sFrontHaulTxBbuIoBufCtrl[j][i][z].nSegTransferred = 0; psBbuIo->sFrontHaulTxBbuIoBufCtrl[j][i][z].sBufferList.nNumBuffers = XRAN_NUM_OF_SYMBOL_PER_SLOT; psBbuIo->sFrontHaulTxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers = &psBbuIo->sFrontHaulTxBuffers[j][i][z][0]; for(k = 0; k < XRAN_NUM_OF_SYMBOL_PER_SLOT; k++) { psBbuIo->sFrontHaulTxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].nElementLenInBytes = nSW_ToFpga_FTH_TxBufferLen; // 14 symbols 3200bytes/symbol psBbuIo->sFrontHaulTxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].nNumberOfElements = 1; psBbuIo->sFrontHaulTxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].nOffsetInBytes = 0; status = xran_bm_allocate_buffer(xranHandle,psBbuIo->nBufPoolIndex[nSectorIndex[i]][eInterfaceType],&ptr); if(XRAN_STATUS_SUCCESS != status) { printf("Failed at xran_bm_allocate_buffer , status %d\n",status); iAssert(status == XRAN_STATUS_SUCCESS); } psBbuIo->sFrontHaulTxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].pData = (uint8_t *)ptr; if(ptr){ u32dptr = (uint32_t*)(ptr); uint8_t *ptr_temp = (uint8_t *)ptr; memset(u32dptr, 0xCC, nSW_ToFpga_FTH_TxBufferLen); ptr_temp[0] = j; // TTI ptr_temp[1] = i; // Sec ptr_temp[2] = z; // Ant ptr_temp[3] = k; // sym } } } } } for(i = 0; inBufPoolIndex[nSectorIndex[i]][eInterfaceType], XRAN_N_FE_BUF_LEN*XRAN_MAX_ANTENNA_NR*XRAN_NUM_OF_SYMBOL_PER_SLOT, nSW_ToFpga_FTH_TxBufferLen); if(XRAN_STATUS_SUCCESS != status) { printf("Failed at xran_bm_init, status %d\n", status); iAssert(status == XRAN_STATUS_SUCCESS); } for(j = 0;j < XRAN_N_FE_BUF_LEN; j++) { for(z = 0; z < XRAN_MAX_ANTENNA_NR; z++){ psBbuIo->sFrontHaulRxBbuIoBufCtrl[j][i][z].bValid = 0; psBbuIo->sFrontHaulRxBbuIoBufCtrl[j][i][z].nSegGenerated = -1; psBbuIo->sFrontHaulRxBbuIoBufCtrl[j][i][z].nSegToBeGen = -1; psBbuIo->sFrontHaulRxBbuIoBufCtrl[j][i][z].nSegTransferred = 0; psBbuIo->sFrontHaulRxBbuIoBufCtrl[j][i][z].sBufferList.nNumBuffers = XRAN_NUM_OF_SYMBOL_PER_SLOT; psBbuIo->sFrontHaulRxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers = &psBbuIo->sFrontHaulRxBuffers[j][i][z][0]; for(k = 0; k< XRAN_NUM_OF_SYMBOL_PER_SLOT; k++) { psBbuIo->sFrontHaulRxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].nElementLenInBytes = nFpgaToSW_FTH_RxBufferLen; // 1 symbols 3200bytes psBbuIo->sFrontHaulRxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].nNumberOfElements = 1; psBbuIo->sFrontHaulRxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].nOffsetInBytes = 0; status = xran_bm_allocate_buffer(xranHandle,psBbuIo->nBufPoolIndex[nSectorIndex[i]][eInterfaceType],&ptr); if(XRAN_STATUS_SUCCESS != status) { printf("Failed at cpa_bb_bm_allocate_buffer , status %d\n",status); iAssert(status == XRAN_STATUS_SUCCESS); } psBbuIo->sFrontHaulRxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].pData = (uint8_t *)ptr; if(ptr){ u32dptr = (uint32_t*)(ptr); uint8_t *ptr_temp = (uint8_t *)ptr; memset(u32dptr, 0xCC, nFpgaToSW_FTH_RxBufferLen); ptr_temp[0] = j; // TTI ptr_temp[1] = i; // Sec ptr_temp[2] = z; // Ant ptr_temp[3] = k; // sym } } } } } // add prach rx buffer for(i = 0; inBufPoolIndex[nSectorIndex[i]][eInterfaceType],XRAN_N_FE_BUF_LEN*XRAN_MAX_ANTENNA_NR*XRAN_NUM_OF_SYMBOL_PER_SLOT, FPGA_TO_SW_PRACH_RX_BUFFER_LEN); if(XRAN_STATUS_SUCCESS != status) { printf("Failed at xran_bm_init, status %d\n", status); iAssert(status == XRAN_STATUS_SUCCESS); } for(j = 0;j < XRAN_N_FE_BUF_LEN; j++) { for(z = 0; z < XRAN_MAX_ANTENNA_NR; z++){ psBbuIo->sFHPrachRxBbuIoBufCtrl[j][i][z].bValid = 0; psBbuIo->sFHPrachRxBbuIoBufCtrl[j][i][z].nSegGenerated = -1; psBbuIo->sFHPrachRxBbuIoBufCtrl[j][i][z].nSegToBeGen = -1; psBbuIo->sFHPrachRxBbuIoBufCtrl[j][i][z].nSegTransferred = 0; psBbuIo->sFHPrachRxBbuIoBufCtrl[j][i][z].sBufferList.nNumBuffers = XRAN_MAX_ANTENNA_NR; // ant number. psBbuIo->sFHPrachRxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers = &psBbuIo->sFHPrachRxBuffers[j][i][z][0]; //for(k = 0; k< XRAN_NUM_OF_SYMBOL_PER_SLOT; k++) k = 0; // one PRACH buffer per antenna per slot { psBbuIo->sFHPrachRxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].nElementLenInBytes = FPGA_TO_SW_PRACH_RX_BUFFER_LEN; psBbuIo->sFHPrachRxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].nNumberOfElements = 1; psBbuIo->sFHPrachRxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].nOffsetInBytes = 0; status = xran_bm_allocate_buffer(xranHandle,psBbuIo->nBufPoolIndex[nSectorIndex[i]][eInterfaceType],&ptr); if(XRAN_STATUS_SUCCESS != status) { printf("Failed at xran_bm_allocate_buffer, status %d\n",status); iAssert(status == XRAN_STATUS_SUCCESS); } psBbuIo->sFHPrachRxBbuIoBufCtrl[j][i][z].sBufferList.pBuffers[k].pData = (uint8_t *)ptr; if(ptr){ u32dptr = (uint32_t*)(ptr); memset(u32dptr, 0xCC, FPGA_TO_SW_PRACH_RX_BUFFER_LEN); } } } } } for(i=0; isFrontHaulTxBbuIoBufCtrl[j][i][z].sBufferList); pFthRxBuffer[i][z][j] = &(psBbuIo->sFrontHaulRxBbuIoBufCtrl[j][i][z].sBufferList); pFthRxRachBuffer[i][z][j] = &(psBbuIo->sFHPrachRxBbuIoBufCtrl[j][i][z].sBufferList); } } } if(NULL != psBbuIo->nInstanceHandle[0]) { for (i = 0; inInstanceHandle[0][i], pFthTxBuffer[i], pFthRxBuffer[i], xran_fh_rx_callback, &pFthRxBuffer[i][0]); } // add prach callback here for (i = 0; inInstanceHandle[0][i], pFthRxRachBuffer[i], xran_fh_rx_prach_callback,&pFthRxRachBuffer[i][0]); } ptrLibConfig->nFhBufIntFlag = 1; } /*config phase compensation*/ /* TODO: add phase compensation handling */ for(i=0; iNRARFCN = 0;//psFPGAInitPara->nDlArfcn[i]; pPhaseCompDl->phaseFlag = 0;//psFPGAInitPara->nPhaseCompFlag; pPhaseCompDl->SULFlag = 0; pPhaseCompDl->SULFreShift = 0; pPhaseCompDl->rsv = 0; pPhaseCompUl = (FPGAPhaseCompCfg *)(&nPhaseCompUl); pPhaseCompUl->NRARFCN = 0;//psFPGAInitPara->nUlArfcn[i]; pPhaseCompUl->phaseFlag = 0;// psFPGAInitPara->nPhaseCompFlag; pPhaseCompUl->SULFlag = 0; pPhaseCompUl->SULFreShift = 0; pPhaseCompUl->rsv = 0; xran_5g_pre_compenstor_cfg(psBbuIo->nInstanceHandle[0][i],nPhaseCompDl,nPhaseCompUl,i); printf("@@@ NB cell %d DL NR-ARFCN %d,DL phase comp flag %d UL NR-ARFCN %d,UL phase comp flag %d \n", i,pPhaseCompDl->NRARFCN,pPhaseCompDl->phaseFlag, pPhaseCompUl->NRARFCN,pPhaseCompUl->phaseFlag); } return status; } int init_xran_iq_content(void) { BbuXranIoIfStruct *psBbuIo = xran_get_ctx(); XranStatusInt32 status; int32_t nSectorIndex[XRAN_MAX_SECTOR_NR]; int32_t nSectorNum; int32_t cc_id, ant_id, sym_id, tti; int32_t flowId; uint8_t frame_id = 0; uint8_t subframe_id = 0; uint8_t slot_id = 0; uint8_t sym = 0; void *ptr; uint32_t *u32dptr; uint16_t *u16dptr; uint8_t *u8dptr; char *pos = NULL; for (nSectorNum = 0; nSectorNum < XRAN_MAX_SECTOR_NR; nSectorNum++) { nSectorIndex[nSectorNum] = nSectorNum; } nSectorNum = numCCPorts; printf ("init_xran_iq_content\n"); /* Init Memory */ for(cc_id = 0; cc_id sFrontHaulTxBbuIoBufCtrl[tti][cc_id][ant_id].sBufferList.pBuffers[sym_id].pData; if(ptr){ u32dptr = (uint32_t*)(ptr); rte_memcpy(u32dptr, pos, PDSCH_PAYLOAD_SIZE); #ifdef DEBUG_XRAN_BUFFERS uint8_t *ptr_temp = (uint8_t *)ptr; ptr_temp[0] = tti; // TTI ptr_temp[1] = cc_id; // Sec ptr_temp[2] = ant_id; // Ant ptr_temp[3] = sym_id; // sym #endif }else printf("ptr ==NULL\n"); tx_play_buffer_position[flowId] += PDSCH_PAYLOAD_SIZE; if(tx_play_buffer_position[flowId] >= tx_play_buffer_size[flowId]) tx_play_buffer_position[flowId] = 0; } else { //printf("flowId %d\n", flowId); } } } } } return 0; } void stop_xran(void) { XranStatusInt32 status = 0; SWXRANInterfaceTypeEnum eInterfaceType; free(gpXranLibConfig); gpXranLibConfig = NULL; status += xran_mm_destroy(xranHandle)*2; if(XRAN_STATUS_SUCCESS != status) { printf("Failed at xran_mm_destroy, status %d\n",status); iAssert(status == XRAN_STATUS_SUCCESS); } } int32_t get_xran_sfidx(uint8_t nNrOfSlotInSf) { int32_t nSfIdx = -1; uint32_t nFrameIdx; uint32_t nSubframeIdx; uint32_t nSlotIdx; uint64_t nSecond; uint32_t nXranTime = xran_get_slot_idx(&nFrameIdx, &nSubframeIdx, &nSlotIdx, &nSecond); nSfIdx = nFrameIdx*NUM_OF_SUBFRAME_PER_FRAME*nNrOfSlotInSf + nSubframeIdx*nNrOfSlotInSf + nSlotIdx; #if 0 printf("\nxranTime is %d, return is %d, radio frame is %d, subframe is %d slot is %d tsc is %llu us", nXranTime, nSfIdx, nFrameIdx, nSubframeIdx, nSlotIdx, __rdtsc()/CPU_HZ); #endif return nSfIdx; } int get_xran_iq_content(void) { BbuXranIoIfStruct *psBbuIo = xran_get_ctx(); XranStatusInt32 status; int32_t nSectorIndex[XRAN_MAX_SECTOR_NR]; int32_t nSectorNum; int32_t cc_id, ant_id, sym_id, tti; int32_t flowId; uint8_t frame_id = 0; uint8_t subframe_id = 0; uint8_t slot_id = 0; uint8_t sym = 0; void *ptr; uint32_t *u32dptr; uint16_t *u16dptr; uint8_t *u8dptr; char *pos = NULL; for (nSectorNum = 0; nSectorNum < XRAN_MAX_SECTOR_NR; nSectorNum++) { nSectorIndex[nSectorNum] = nSectorNum; } nSectorNum = numCCPorts; printf ("get_xran_iq_content\n"); /* Init Memory */ for(cc_id = 0; cc_id sFrontHaulRxBbuIoBufCtrl[tti][cc_id][ant_id].sBufferList.pBuffers[sym_id].pData; if(ptr){ u32dptr = (uint32_t*)(ptr); rte_memcpy(pos, u32dptr, PDSCH_PAYLOAD_SIZE); #ifdef DEBUG_XRAN_BUFFERS if (pos[0] != tti|| pos[1] != cc_id || pos[2] != ant_id || pos[3] != sym_id){ printf("[flowId %d] %d %d %d %d\n", flowId, pos[0], pos[1], pos[2], pos[3]); } #endif }else printf("ptr ==NULL\n"); rx_log_buffer_position[flowId] += PDSCH_PAYLOAD_SIZE; if(rx_log_buffer_position[flowId] >= rx_log_buffer_size[flowId]) rx_log_buffer_position[flowId] = 0; } else { //printf("flowId %d\n", flowId); } } } } } return 0; } int main(int argc, char *argv[]) { int i; int j; int lcore_id = 0; char filename[64]; if (argc == 3) errx(2, "Need two argument - the PCI address of the network port"); if (xran_is_synchronized() != 0) printf("Machine is not synchronized using PTP!\n"); else printf("Machine is synchronized using PTP!\n"); memset(&startupConfiguration, 0, sizeof(RuntimeConfig)); if (parseConfigFile(argv[1], &startupConfiguration) != 0) { printf("Configuration file error.\n"); return 0; } if(startupConfiguration.ant_file[0] == NULL){ printf("it looks like test vector for antennas were not provided\n"); exit(-1); } numCCPorts = startupConfiguration.numCC; num_eAxc = startupConfiguration.numAxc; printf("numCCPorts %d num_eAxc%d\n", numCCPorts, num_eAxc); /* Numerology 3 */ nFpgaToSW_FTH_RxBufferLen = 3328; //3200 * 14; nFpgaToSW_PRACH_RxBufferLen = 8192; nSW_ToFpga_FTH_TxBufferLen = 3328; //3200; * 14; memset(&xranInit, 0, sizeof(XRANFHINIT)); if(startupConfiguration.appMode == APP_LLS_CU) { printf("set lls-CU\n"); xranInit.io_cfg.id = 0;//ID_LLS_CU; xranInit.io_cfg.core = 4+1; xranInit.io_cfg.system_core = 0; xranInit.io_cfg.pkt_proc_core = 4+2; xranInit.io_cfg.pkt_aux_core = 0; /* do not start*/ xranInit.io_cfg.timing_core = 4+3; } else { printf("set RU\n"); xranInit.io_cfg.id = 1; /* ID_LLS_CU;*/ xranInit.io_cfg.core = 1; xranInit.io_cfg.system_core = 0; xranInit.io_cfg.pkt_proc_core = 2; xranInit.io_cfg.pkt_aux_core = 0; /* do not start */ xranInit.io_cfg.timing_core = 3; } xranInit.llscuId = 0; // for ecpriRtcid/ecpriPcid xranInit.nSec = 1; // shall be one xranInit.eAxCId_conf.mask_cuPortId = 0xf000; xranInit.eAxCId_conf.mask_bandSectorId = 0x0f00; xranInit.eAxCId_conf.mask_ccId = 0x00f0; xranInit.eAxCId_conf.mask_ruPortId = 0x000f; xranInit.eAxCId_conf.bit_cuPortId = 12; xranInit.eAxCId_conf.bit_bandSectorId = 8; xranInit.eAxCId_conf.bit_ccId = 4; xranInit.eAxCId_conf.bit_ruPortId = 0; xranInit.io_cfg.dpdk_dev[XRAN_UP_VF] = argv[2]; xranInit.io_cfg.dpdk_dev[XRAN_CP_VF] = argv[3]; xranInit.p_lls_cu_addr = (int8_t*)&startupConfiguration.lls_cu_addr; xranInit.p_ru_addr = (int8_t*)&startupConfiguration.ru_addr; xranInit.ttiPeriod = startupConfiguration.ttiPeriod; xranInit.Tadv_cp_dl = startupConfiguration.Tadv_cp_dl; xranInit.T2a_min_cp_dl = startupConfiguration.T2a_min_cp_dl; xranInit.T2a_max_cp_dl = startupConfiguration.T2a_max_cp_dl; xranInit.T2a_min_cp_ul = startupConfiguration.T2a_min_cp_ul; xranInit.T2a_max_cp_ul = startupConfiguration.T2a_max_cp_ul; xranInit.T2a_min_up = startupConfiguration.T2a_min_up; xranInit.T2a_max_up = startupConfiguration.T2a_max_up; xranInit.Ta3_min = startupConfiguration.Ta3_min; xranInit.Ta3_max = startupConfiguration.Ta3_max; xranInit.T1a_min_cp_dl = startupConfiguration.T1a_min_cp_dl; xranInit.T1a_max_cp_dl = startupConfiguration.T1a_max_cp_dl; xranInit.T1a_min_cp_ul = startupConfiguration.T1a_min_cp_ul; xranInit.T1a_max_cp_ul = startupConfiguration.T1a_max_cp_ul; xranInit.T1a_min_up = startupConfiguration.T1a_min_up; xranInit.T1a_max_up = startupConfiguration.T1a_max_up; xranInit.Ta4_min = startupConfiguration.Ta4_min; xranInit.Ta4_max = startupConfiguration.Ta4_max; xranInit.enableCP = startupConfiguration.enableCP; xranInit.debugStop = startupConfiguration.debugStop; xranInit.cp_vlan_tag = startupConfiguration.cp_vlan_tag; xranInit.up_vlan_tag = startupConfiguration.up_vlan_tag; for(i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { p_tx_play_buffer[i] = (int16_t*)malloc(IQ_PLAYBACK_BUFFER_BYTES); tx_play_buffer_size[i] = (int32_t)IQ_PLAYBACK_BUFFER_BYTES; if (p_tx_play_buffer[i] == NULL) exit(-1); tx_play_buffer_size[i] = sys_load_file_to_buff(startupConfiguration.ant_file[i], "DL IFFT IN IQ Samples in binary format", (uint8_t*) p_tx_play_buffer[i], tx_play_buffer_size[i], 1); tx_play_buffer_position[i] = 0; } /* log of ul */ for(i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { p_rx_log_buffer[i] = (int16_t*)malloc(IQ_PLAYBACK_BUFFER_BYTES); rx_log_buffer_size[i] = (int32_t)IQ_PLAYBACK_BUFFER_BYTES; if (p_rx_log_buffer[i] == NULL) exit(-1); rx_log_buffer_position[i] = 0; memset(p_rx_log_buffer[i], 0, rx_log_buffer_size[i]); } /* log of Prach */ for(i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { p_prach_log_buffer[i] = (int16_t*)malloc(PRACH_PLAYBACK_BUFFER_BYTES); prach_log_buffer_size[i] = (int32_t)PRACH_PLAYBACK_BUFFER_BYTES; if (p_prach_log_buffer[i] == NULL) exit(-1); memset(p_prach_log_buffer[i], 0, prach_log_buffer_size[i]); prach_log_buffer_position[i] = 0; } for (i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { sprintf(filename, "%s-play_ant%d.txt",((startupConfiguration.appMode == APP_LLS_CU) ? "lls-cu" : "ru"), i); sys_save_buf_to_file_txt(filename, "DL IFFT IN IQ Samples in human readable format", (uint8_t*) p_tx_play_buffer[i], tx_play_buffer_size[i], 1); sprintf(filename, "%s-play_ant%d.bin",((startupConfiguration.appMode == APP_LLS_CU) ? "lls-cu" : "ru"), i); sys_save_buf_to_file(filename, "DL IFFT IN IQ Samples in binary format", (uint8_t*) p_tx_play_buffer[i], tx_play_buffer_size[i]/sizeof(short), sizeof(short)); } if (startupConfiguration.iqswap == 1){ for(i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { printf("TX: Swap I and Q to match RU format: [%d]\n",i); { /* swap I and Q */ int32_t j; signed short *ptr = (signed short *) p_tx_play_buffer[i]; signed short temp; for (j = 0; j < (int32_t)(tx_play_buffer_size[i]/sizeof(short)) ; j = j + 2){ temp = ptr[j]; ptr[j] = ptr[j + 1]; ptr[j + 1] = temp; } } } } #if 0 for (i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { sprintf(filename, "swap_IQ_play_ant%d.txt", i); sys_save_buf_to_file_txt(filename, "DL IFFT IN IQ Samples in human readable format", (uint8_t*) p_tx_play_buffer[i], tx_play_buffer_size[i], 1); } #endif if (startupConfiguration.nebyteorderswap == 1){ for(i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { printf("TX: Convert S16 I and S16 Q to network byte order for XRAN Ant: [%d]\n",i); for (j = 0; j < tx_play_buffer_size[i]/sizeof(short); j++){ p_tx_play_buffer[i][j] = rte_cpu_to_be_16(p_tx_play_buffer[i][j]); } } } #if 0 for (i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { sprintf(filename, "swap_be_play_ant%d.txt", i); sys_save_buf_to_file_txt(filename, "DL IFFT IN IQ Samples in human readable format", (uint8_t*) p_tx_play_buffer[i], tx_play_buffer_size[i], 1); } #endif timer_set_tsc_freq_from_clock(); xran_init(argc, argv, &xranInit, argv[0], &xranHandle); if(xranHandle == NULL) exit(1); memset(&xranConf, 0, sizeof(XRANFHCONFIG)); pXranConf = &xranConf; for(i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { pXranConf->playback_conf.TxPlayBufAddr[i] = (unsigned long)p_tx_play_buffer[i]; pXranConf->playback_conf.TxPlayBufSize = tx_play_buffer_size[i]; } pXranConf->sector_id = 0; pXranConf->nCC = numCCPorts; pXranConf->neAxc = num_eAxc; pXranConf->frame_conf.nFrameDuplexType = 1; // TDD pXranConf->frame_conf.nNumerology = startupConfiguration.mu_number; // 120KHz; same as XRAN_SCS_120KHz? // pXranConf->frame_conf.nTddPeriod = ; pXranConf->prach_conf.nPrachSubcSpacing = XRAN_SCS_120KHZ; pXranConf->prach_conf.nPrachFreqStart = 0; pXranConf->prach_conf.nPrachFilterIdx = XRAN_FILTERINDEX_PRACH_ABC; pXranConf->prach_conf.nPrachConfIdx = 81; pXranConf->prach_conf.nPrachFreqOffset = -792; pXranConf->ru_conf.iqWidth = 16; pXranConf->ru_conf.compMeth = XRAN_COMPMETHOD_NONE; pXranConf->ru_conf.fftSize = XRAN_FFTSIZE_2048; if(init_xran() != 0) exit(-1); xran_reg_physide_cb(xranHandle, physide_dl_tti_call_back, NULL, 10, XRAN_CB_TTI); xran_reg_physide_cb(xranHandle, physide_ul_half_slot_call_back, NULL, 10, XRAN_CB_HALF_SLOT_RX); xran_reg_physide_cb(xranHandle, physide_ul_full_slot_call_back, NULL, 10, XRAN_CB_FULL_SLOT_RX); init_xran_iq_content(); xran_open(xranHandle, pXranConf); sprintf(filename, "mlog-%s", startupConfiguration.appMode == 0 ? "lls-cu" : "ru"); MLogOpen(0, 32, 0, 0xFFFFFFFF, filename); puts("----------------------------------------"); printf("MLog Info: virt=0x%016lx size=%d\n", MLogGetFileLocation(), MLogGetFileSize()); puts("----------------------------------------"); state = APP_RUNNING; sleep(6); for (;;) { print_menu(); char input[10]; int sel_opt; //#ifdef Nightly_build // sel_opt = 3; // sleep(10); //#else if (NULL == fgets(input, 10, stdin)) { state = APP_STOPPED; break; } sel_opt = atoi(input); //#endif switch (sel_opt) { case 1: xran_start(xranHandle); printf("Start XRAN traffic\n"); break; case 2: break; case 3: xran_stop(xranHandle); printf("Stop XRAN traffic\n"); state = APP_STOPPED; break; case 4: // send_cpmsg_dlul(XRAN_DIR_DL, flowId, // frame_id, subframe_id, slot_id, // 0, XRAN_SYMBOLPERSLOT_MAX, NUM_OF_PRB_IN_FULL_BAND, // beam_id, cc_id, ant_id, // cp_seq_id_num[XRAN_DIR_DL][ant_id]++); break; default: puts("Wrong option passed!"); break; } if (APP_STOPPED == state) break; } get_xran_iq_content(); puts("Closing l1 app... Ending all threads..."); xran_close(xranHandle); MLogPrint(NULL); stop_xran(); puts("Dump IQs..."); if (startupConfiguration.iqswap == 1){ for(i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { printf("RX: Swap I and Q to match CPU format: [%d]\n",i); { /* swap I and Q */ int32_t j; signed short *ptr = (signed short *) p_rx_log_buffer[i]; signed short temp; for (j = 0; j < (int32_t)(rx_log_buffer_size[i]/sizeof(short)) ; j = j + 2){ temp = ptr[j]; ptr[j] = ptr[j + 1]; ptr[j + 1] = temp; } } } } if (startupConfiguration.nebyteorderswap == 1){ for(i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { printf("RX: Convert S16 I and S16 Q to cpu byte order from XRAN Ant: [%d]\n",i); for (j = 0; j < rx_log_buffer_size[i]/sizeof(short); j++){ p_rx_log_buffer[i][j] = rte_be_to_cpu_16(p_rx_log_buffer[i][j]); } } } for (i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { sprintf(filename, "%s-rx_log_ant%d.txt",((startupConfiguration.appMode == APP_LLS_CU) ? "lls-cu" : "ru"), i); sys_save_buf_to_file_txt(filename, "UL FFT OUT IQ Samples in human readable format", (uint8_t*) p_rx_log_buffer[i], rx_log_buffer_size[i], 1); sprintf(filename, "%s-rx_log_ant%d.bin",((startupConfiguration.appMode == APP_LLS_CU) ? "lls-cu" : "ru"), i); sys_save_buf_to_file(filename, "UL FFT OUT IQ Samples in binary format", (uint8_t*) p_rx_log_buffer[i], rx_log_buffer_size[i]/sizeof(short), sizeof(short)); } if (startupConfiguration.iqswap == 1){ for(i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { printf("PRACH: Swap I and Q to match CPU format: [%d]\n",i); { /* swap I and Q */ int32_t j; signed short *ptr = (signed short *) p_prach_log_buffer[i]; signed short temp; for (j = 0; j < (int32_t)(prach_log_buffer_size[i]/sizeof(short)) ; j = j + 2){ temp = ptr[j]; ptr[j] = ptr[j + 1]; ptr[j + 1] = temp; } } } } if (startupConfiguration.nebyteorderswap == 1){ for(i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { printf("PRACH: Convert S16 I and S16 Q to cpu byte order from XRAN Ant: [%d]\n",i); for (j = 0; j < prach_log_buffer_size[i]/sizeof(short); j++){ p_prach_log_buffer[i][j] = rte_be_to_cpu_16(p_prach_log_buffer[i][j]); } } } for (i = 0; i < MAX_ANT_CARRIER_SUPPORTED && i < (uint32_t)(numCCPorts * num_eAxc); i++) { sprintf(filename, "%s-prach_log_ant%d.txt",((startupConfiguration.appMode == APP_LLS_CU) ? "lls-cu" : "ru"), i); sys_save_buf_to_file_txt(filename, "PRACH FFT OUT IQ Samples in human readable format", (uint8_t*) p_prach_log_buffer[i], prach_log_buffer_size[i], 1); sprintf(filename, "%s-prach_log_ant%d.bin",((startupConfiguration.appMode == APP_LLS_CU) ? "lls-cu" : "ru"), i); sys_save_buf_to_file(filename, "PRACH FFT OUT IQ Samples in binary format", (uint8_t*) p_prach_log_buffer[i], prach_log_buffer_size[i]/sizeof(short), sizeof(short)); } return 0; }