X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?p=o-du%2Fphy.git;a=blobdiff_plain;f=fhi_lib%2Flib%2Fsrc%2Fxran_cp_proc.c;fp=fhi_lib%2Flib%2Fsrc%2Fxran_cp_proc.c;h=e40ce7256752a4f3f470ef32dd8c6f600170e706;hp=0000000000000000000000000000000000000000;hb=2de97529a4c5a1922214ba0e6f0fb84cacbd0bc7;hpb=81a09690b36b3a4e89b4dae34f30933de13f7f90 diff --git a/fhi_lib/lib/src/xran_cp_proc.c b/fhi_lib/lib/src/xran_cp_proc.c new file mode 100644 index 0000000..e40ce72 --- /dev/null +++ b/fhi_lib/lib/src/xran_cp_proc.c @@ -0,0 +1,584 @@ +/****************************************************************************** +* +* Copyright (c) 2020 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 XRAN C plane processing functionality and helper functions + * @file xran_cp_proc.c + * @ingroup group_source_xran + * @author Intel Corporation + **/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xran_fh_o_du.h" + +#include "ethdi.h" +#include "xran_pkt.h" +#include "xran_up_api.h" +#include "xran_cp_api.h" +#include "xran_sync_api.h" +#include "xran_lib_mlog_tasks_id.h" +#include "xran_timer.h" +#include "xran_common.h" +#include "xran_dev.h" +#include "xran_frame_struct.h" +#include "xran_printf.h" +#include "xran_app_frag.h" +#include "xran_cp_proc.h" +#include "xran_tx_proc.h" + +#include "xran_mlog_lnx.h" + +uint8_t xran_cp_seq_id_num[XRAN_PORTS_NUM][XRAN_MAX_CELLS_PER_PORT][XRAN_DIR_MAX][XRAN_MAX_ANTENNA_NR * 2 + XRAN_MAX_ANT_ARRAY_ELM_NR]; /* XRAN_MAX_ANTENNA_NR * 2 for PUSCH and PRACH */ +uint8_t xran_updl_seq_id_num[XRAN_PORTS_NUM][XRAN_MAX_CELLS_PER_PORT][XRAN_MAX_ANTENNA_NR]; +uint8_t xran_upul_seq_id_num[XRAN_PORTS_NUM][XRAN_MAX_CELLS_PER_PORT][XRAN_MAX_ANTENNA_NR * 2 + XRAN_MAX_ANT_ARRAY_ELM_NR]; /**< PUSCH, PRACH, SRS for Cat B */ +uint8_t xran_section_id_curslot[XRAN_PORTS_NUM][XRAN_DIR_MAX][XRAN_MAX_CELLS_PER_PORT][XRAN_MAX_ANTENNA_NR * 2+ XRAN_MAX_ANT_ARRAY_ELM_NR]; +uint16_t xran_section_id[XRAN_PORTS_NUM][XRAN_DIR_MAX][XRAN_MAX_CELLS_PER_PORT][XRAN_MAX_ANTENNA_NR * 2+ XRAN_MAX_ANT_ARRAY_ELM_NR]; + +struct xran_recv_packet_info parse_recv[XRAN_PORTS_NUM]; + +////////////////////////////////////////// +// For RU emulation +struct xran_section_recv_info *recvSections[XRAN_PORTS_NUM] = {NULL,NULL,NULL,NULL}; +struct xran_cp_recv_params recvCpInfo[XRAN_PORTS_NUM]; + +static void +extbuf_free_callback(void *addr __rte_unused, void *opaque __rte_unused) +{ + /*long t1 = MLogTick(); + MLogTask(77777, t1, t1+100);*/ +} + +int32_t +xran_init_sectionid(void *pHandle) +{ + int cell, ant, dir; + struct xran_device_ctx* p_dev = NULL; + uint8_t xran_port_id = 0; + + if(pHandle) { + p_dev = (struct xran_device_ctx* )pHandle; + xran_port_id = p_dev->xran_port_id; + } else { + print_err("Invalid pHandle - %p", pHandle); + return (-1); + } + + for (dir = 0; dir < XRAN_DIR_MAX; dir++){ + for(cell=0; cell < XRAN_MAX_CELLS_PER_PORT; cell++) { + for(ant=0; ant < XRAN_MAX_ANTENNA_NR; ant++) { + xran_section_id[xran_port_id][dir][cell][ant] = 0; + xran_section_id_curslot[xran_port_id][dir][cell][ant] = 255; + } + } + } + + return (0); +} + +int32_t +xran_init_seqid(void *pHandle) +{ + int cell, dir, ant; + int8_t xran_port = 0; + if((xran_port = xran_dev_ctx_get_port_id(pHandle)) < 0 ){ + print_err("Invalid pHandle - %p", pHandle); + return (0); + } + + + for(cell=0; cell < XRAN_MAX_CELLS_PER_PORT; cell++) { + for(dir=0; dir < XRAN_DIR_MAX; dir++) { + for(ant=0; ant < XRAN_MAX_ANTENNA_NR * 2; ant++) + xran_cp_seq_id_num[xran_port][cell][dir][ant] = 0; + } + for(ant=0; ant < XRAN_MAX_ANTENNA_NR; ant++) + xran_updl_seq_id_num[xran_port][cell][ant] = 0; + for(ant=0; ant < XRAN_MAX_ANTENNA_NR * 2 + XRAN_MAX_ANT_ARRAY_ELM_NR; ant++) + xran_upul_seq_id_num[xran_port][cell][ant] = 0; + } + + return (0); +} + +int32_t +process_cplane(struct rte_mbuf *pkt, void* handle) +{ + struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)handle; + + if(p_xran_dev_ctx) { + if(xran_dev_get_ctx_by_id(0)->fh_cfg.debugStop) /* check CP with standard tests only */ + xran_parse_cp_pkt(pkt, &recvCpInfo[p_xran_dev_ctx->xran_port_id], &parse_recv[p_xran_dev_ctx->xran_port_id]); + } + + return (MBUF_FREE); +} + +int32_t +xran_check_symbolrange(int symbol_type, uint32_t PortId, int cc_id, int tti, + int start_sym, int numsym_in, int *numsym_out) +{ + int i; + int first_pos, last_pos; + int start_pos, end_pos; + + first_pos = last_pos = -1; + + /* Find first symbol which is same with given symbol type */ + for(i=0; i < XRAN_NUM_OF_SYMBOL_PER_SLOT; i++) + if(xran_fs_get_symbol_type(PortId, cc_id, tti, i) == symbol_type) { + first_pos = i; break; + } + + if(first_pos < 0) { +// for(i=0; i < XRAN_NUM_OF_SYMBOL_PER_SLOT; i++) +// printf("symbol_type %d - %d:%d\n", symbol_type, i, xran_fs_get_symbol_type(cc_id, tti, i)); + *numsym_out = 0; + return (first_pos); + } + + /* Find the rest of consecutive symbols which are same with given symbol type */ + for( ; i < XRAN_NUM_OF_SYMBOL_PER_SLOT; i++) + if(xran_fs_get_symbol_type(PortId, cc_id, tti, i) != symbol_type) + break; + last_pos = i; + + start_pos = (first_pos > start_sym) ? first_pos : start_sym; + end_pos = ((start_sym + numsym_in) > last_pos) ? last_pos : (start_sym + numsym_in); + *numsym_out = end_pos - start_pos; + + return (start_pos); +} + +struct rte_mbuf * +xran_attach_cp_ext_buf(uint16_t vf_id, int8_t* p_ext_buff_start, int8_t* p_ext_buff, uint16_t ext_buff_len, + struct rte_mbuf_ext_shared_info * p_share_data) +{ + struct rte_mbuf *mb_oran_hdr_ext = NULL; + struct rte_mbuf *tmp = NULL; + int8_t *ext_buff = NULL; + rte_iova_t ext_buff_iova = 0; + + ext_buff = p_ext_buff - (RTE_PKTMBUF_HEADROOM + + sizeof(struct xran_ecpri_hdr) + + sizeof(struct xran_cp_radioapp_section1_header) + + sizeof(struct xran_cp_radioapp_section1)); + + ext_buff_len += (RTE_PKTMBUF_HEADROOM + + sizeof(struct xran_ecpri_hdr) + + sizeof(struct xran_cp_radioapp_section1_header) + + sizeof(struct xran_cp_radioapp_section1)) + 18; + +// mb_oran_hdr_ext = rte_pktmbuf_alloc(_eth_mbuf_pool_small); + mb_oran_hdr_ext = xran_ethdi_mbuf_indir_alloc(); + + if (unlikely (( mb_oran_hdr_ext) == NULL)) { + rte_panic("Failed rte_pktmbuf_alloc\n"); + } + + p_share_data->free_cb = extbuf_free_callback; + p_share_data->fcb_opaque = NULL; + rte_mbuf_ext_refcnt_set(p_share_data, 1); + + ext_buff_iova = rte_malloc_virt2iova(p_ext_buff_start); + if (unlikely (( ext_buff_iova) == 0)) { + rte_panic("Failed rte_mem_virt2iova \n"); + } + + if (unlikely (( (rte_iova_t)ext_buff_iova) == RTE_BAD_IOVA)) { + rte_panic("Failed rte_mem_virt2iova RTE_BAD_IOVA \n"); + } + + rte_pktmbuf_attach_extbuf(mb_oran_hdr_ext, + ext_buff, + ext_buff_iova + RTE_PTR_DIFF(ext_buff , p_ext_buff_start), + ext_buff_len, + p_share_data); + + rte_pktmbuf_reset_headroom(mb_oran_hdr_ext); + + return mb_oran_hdr_ext; +} + +int32_t +xran_cp_create_and_send_section(void *pHandle, uint8_t ru_port_id, int dir, int tti, int cc_id, + struct xran_prb_map *prbMap, enum xran_category category, uint8_t ctx_id) +{ + int32_t ret = 0; + struct xran_device_ctx *p_x_ctx = (struct xran_device_ctx *)pHandle; + struct xran_common_counters *pCnt = &p_x_ctx->fh_counters; + struct xran_cp_gen_params params; + struct xran_section_gen_info sect_geninfo[1]; + struct rte_mbuf *mbuf; + uint32_t interval = p_x_ctx->interval_us_local; + uint8_t PortId = p_x_ctx->xran_port_id; + + + uint32_t i, j, loc_sym; + uint32_t nsection = 0; + struct xran_prb_elm *pPrbMapElem = NULL; + struct xran_prb_elm *pPrbMapElemPrev = NULL; + uint32_t slot_id = XranGetSlotNum(tti, SLOTNUM_PER_SUBFRAME(interval)); + uint32_t subframe_id = XranGetSubFrameNum(tti,SLOTNUM_PER_SUBFRAME(interval), SUBFRAMES_PER_SYSTEMFRAME); + uint32_t frame_id = XranGetFrameNum(tti,xran_getSfnSecStart(),SUBFRAMES_PER_SYSTEMFRAME, SLOTNUM_PER_SUBFRAME(interval)); + + uint8_t seq_id = 0; + uint16_t vf_id = 0; + + int next; + struct xran_sectionext1_info ext1; + struct xran_sectionext4_info ext4 = {0}; + struct xran_sectionext11_info ext11; + + //frame_id = (frame_id & 0xff); /* ORAN frameId, 8 bits, [0, 255] */ + frame_id = ((frame_id + ((0 == tti)?NUM_OF_FRAMES_PER_SECOND:0)) & 0xff); /* ORAN frameId, 8 bits, [0, 255] */ + + if(prbMap) { + nsection = prbMap->nPrbElm; + pPrbMapElem = &prbMap->prbMap[0]; + } else { + print_err("prbMap is NULL\n"); + return (-1); + } + + /* Generate a C-Plane message per each section, + * not a C-Plane message with multi sections */ + for (i = 0; i < nsection; i++) { + int startSym, numSyms; + + pPrbMapElem = &prbMap->prbMap[i]; + + /* For Special Subframe, + * Check validity of given symbol range with slot configuration + * and adjust symbol range accordingly. */ + if(xran_fs_get_slot_type(PortId, cc_id, tti, XRAN_SLOT_TYPE_FDD) != 1 + && xran_fs_get_slot_type(PortId, cc_id, tti, XRAN_SLOT_TYPE_SP) == 1) { + /* This function cannot handle two or more groups of consecutive same type of symbol. + * If there are two or more, then it might cause an error */ + startSym = xran_check_symbolrange( + ((dir==XRAN_DIR_DL)?XRAN_SYMBOL_TYPE_DL:XRAN_SYMBOL_TYPE_UL), + PortId, cc_id, tti, + pPrbMapElem->nStartSymb, + pPrbMapElem->numSymb, &numSyms); + if(startSym < 0 || numSyms == 0) { + /* if start symbol is not valid, then skip this section */ + print_err("Skip section %d due to invalid symbol range - [%d:%d], [%d:%d]", + i, + pPrbMapElem->nStartSymb, pPrbMapElem->numSymb, + startSym, numSyms); + continue; + } + } else { + startSym = pPrbMapElem->nStartSymb; + numSyms = pPrbMapElem->numSymb; + } + + vf_id = xran_map_ecpriRtcid_to_vf(p_x_ctx, dir, cc_id, ru_port_id); + params.dir = dir; + params.sectionType = XRAN_CP_SECTIONTYPE_1; + params.hdr.filterIdx = XRAN_FILTERINDEX_STANDARD; + params.hdr.frameId = frame_id; + params.hdr.subframeId = subframe_id; + params.hdr.slotId = slot_id; + params.hdr.startSymId = startSym; + params.hdr.iqWidth = pPrbMapElem->iqWidth; + params.hdr.compMeth = pPrbMapElem->compMethod; + + print_dbg("cp[%d:%d:%d] ru_port_id %d dir=%d\n", + frame_id, subframe_id, slot_id, ru_port_id, dir); + + seq_id = xran_get_cp_seqid(pHandle, XRAN_DIR_DL, cc_id, ru_port_id); + + sect_geninfo[0].info.type = params.sectionType; + sect_geninfo[0].info.startSymId = params.hdr.startSymId; + sect_geninfo[0].info.iqWidth = params.hdr.iqWidth; + sect_geninfo[0].info.compMeth = params.hdr.compMeth; + + sect_geninfo[0].info.id = i; /* do not revert 'i' to + xran_alloc_sectionid(pHandle, dir, cc_id, ru_port_id, slot_id); */ + + if(sect_geninfo[0].info.id > XRAN_MAX_SECTIONS_PER_SLOT) + print_err("sectinfo->id %d\n", sect_geninfo[0].info.id); +#if 0 + if (dir == XRAN_DIR_UL) { + for(loc_sym = 0; loc_sym < XRAN_NUM_OF_SYMBOL_PER_SLOT; loc_sym++) { + int32_t sec_desc_idx = pPrbMapElem->nSecDesc[loc_sym]; + struct xran_section_desc *p_sec_desc = pPrbMapElem->p_sec_desc[loc_sym][0]; + if(p_sec_desc) { + p_sec_desc->section_id = sect_geninfo[0].info.id; + if(p_sec_desc->pCtrl) { + rte_pktmbuf_free(p_sec_desc->pCtrl); + p_sec_desc->pCtrl = NULL; + p_sec_desc->pData = NULL; + } + } + else { + print_err("section desc is NULL\n"); + } + sec_desc_idx--; + pPrbMapElem->nSecDesc[loc_sym] = 0; + } + } +#endif + + sect_geninfo[0].info.rb = XRAN_RBIND_EVERY; + sect_geninfo[0].info.startPrbc = pPrbMapElem->nRBStart; + sect_geninfo[0].info.numPrbc = pPrbMapElem->nRBSize; + sect_geninfo[0].info.numSymbol = numSyms; + sect_geninfo[0].info.reMask = 0xfff; + sect_geninfo[0].info.beamId = pPrbMapElem->nBeamIndex; + sect_geninfo[0].info.symInc = XRAN_SYMBOLNUMBER_NOTINC; + + for(loc_sym = 0; loc_sym < XRAN_NUM_OF_SYMBOL_PER_SLOT; loc_sym++) { + struct xran_section_desc *p_sec_desc = pPrbMapElem->p_sec_desc[loc_sym][0]; + if(p_sec_desc) { + p_sec_desc->section_id = sect_geninfo[0].info.id; + + sect_geninfo[0].info.sec_desc[loc_sym].iq_buffer_offset = p_sec_desc->iq_buffer_offset; + sect_geninfo[0].info.sec_desc[loc_sym].iq_buffer_len = p_sec_desc->iq_buffer_len; + } else { + print_err("section desc is NULL\n"); + } + } + + if(unlikely((category != XRAN_CATEGORY_A) && (category != XRAN_CATEGORY_B))) { + print_err("Unsupported Category %d\n", category); + return (-1); + } + + /* Add extentions if required */ + next = 0; + sect_geninfo[0].exDataSize = 0; + + /* Extension 4 for modulation compression */ + if(pPrbMapElem->compMethod == XRAN_COMPMETHOD_MODULATION) { + mbuf = xran_ethdi_mbuf_alloc(); + + ext4.csf = 0; //no shift for now only + ext4.modCompScaler = pPrbMapElem->ScaleFactor; + sect_geninfo[0].exData[next].type = XRAN_CP_SECTIONEXTCMD_4; + sect_geninfo[0].exData[next].len = sizeof(ext4); + sect_geninfo[0].exData[next].data = &ext4; + + sect_geninfo[0].info.ef = 1; + sect_geninfo[0].exDataSize++; + next++; + } + + /* Extension 1 or 11 for Beam forming weights */ + if((category == XRAN_CATEGORY_B) && (pPrbMapElem->bf_weight_update)) { + /* add extantion section for BF Weights if update is needed */ + if(pPrbMapElem->bf_weight.numBundPrb == 0) { + /* No bundled PRBs, using Extension 1 */ + struct rte_mbuf_ext_shared_info * p_share_data = &p_x_ctx->cp_share_data.sh_data[tti % XRAN_N_FE_BUF_LEN][cc_id][ru_port_id][sect_geninfo[0].info.id]; + + /*add extention section for BF Weights if update is needed */ + if(pPrbMapElem->bf_weight.p_ext_start) { + /* use buffer with BF Weights for mbuf */ + mbuf = xran_attach_cp_ext_buf(vf_id, pPrbMapElem->bf_weight.p_ext_start, + pPrbMapElem->bf_weight.p_ext_section, + pPrbMapElem->bf_weight.ext_section_sz, p_share_data); + } else { + print_err("p %d cc %d dir %d Alloc fail!\n", PortId, cc_id, dir); + return (-1); + } + + memset(&ext1, 0, sizeof (struct xran_sectionext1_info)); + ext1.bfwNumber = pPrbMapElem->bf_weight.nAntElmTRx; + ext1.bfwIqWidth = pPrbMapElem->iqWidth; + ext1.bfwCompMeth = pPrbMapElem->compMethod; + ext1.p_bfwIQ = (int16_t*)pPrbMapElem->bf_weight.p_ext_section; + ext1.bfwIQ_sz = pPrbMapElem->bf_weight.ext_section_sz; + + sect_geninfo[0].exData[next].type = XRAN_CP_SECTIONEXTCMD_1; + sect_geninfo[0].exData[next].len = sizeof(ext1); + sect_geninfo[0].exData[next].data = &ext1; + + sect_geninfo[0].info.ef = 1; + sect_geninfo[0].exDataSize++; + next++; + } else { /* if(pPrbMapElem->bf_weight.numBundPrb == 0) */ + /* Using Extension 11 */ + struct rte_mbuf_ext_shared_info *shared_info; + + shared_info = &p_x_ctx->bfw_share_data.sh_data[tti % XRAN_N_FE_BUF_LEN][cc_id][ru_port_id][sect_geninfo[0].info.id]; + + + shared_info->free_cb = NULL; + shared_info->fcb_opaque = NULL; + + mbuf = xran_ethdi_mbuf_indir_alloc(); + if(unlikely(mbuf == NULL)) { + rte_panic("Alloc fail!\n"); + return (-1); + } + //mbuf = rte_pktmbuf_alloc(_eth_mbuf_pool_vf_small[vf_id]); + if(xran_cp_attach_ext_buf(mbuf, (uint8_t *)pPrbMapElem->bf_weight.p_ext_start, pPrbMapElem->bf_weight.maxExtBufSize, shared_info) < 0) { + rte_pktmbuf_free(mbuf); + return (-1); + } + + rte_mbuf_ext_refcnt_update(shared_info, 0); + + ext11.RAD = pPrbMapElem->bf_weight.RAD; + ext11.disableBFWs = pPrbMapElem->bf_weight.disableBFWs; + + ext11.numBundPrb = pPrbMapElem->bf_weight.numBundPrb; + ext11.numSetBFWs = pPrbMapElem->bf_weight.numSetBFWs; + + ext11.bfwCompMeth = pPrbMapElem->bf_weight.bfwCompMeth; + ext11.bfwIqWidth = pPrbMapElem->bf_weight.bfwIqWidth; + + ext11.maxExtBufSize = pPrbMapElem->bf_weight.maxExtBufSize; + ext11.pExtBufShinfo = shared_info; + + ext11.pExtBuf = (uint8_t *)pPrbMapElem->bf_weight.p_ext_start; + ext11.totalBfwIQLen = pPrbMapElem->bf_weight.ext_section_sz; + + sect_geninfo[0].exData[next].type = XRAN_CP_SECTIONEXTCMD_11; + sect_geninfo[0].exData[next].len = sizeof(ext11); + sect_geninfo[0].exData[next].data = &ext11; + + sect_geninfo[0].info.ef = 1; + sect_geninfo[0].exDataSize++; + next++; + } + } else { /* if((category == XRAN_CATEGORY_B) && (pPrbMapElem->bf_weight_update)) */ + mbuf = xran_ethdi_mbuf_alloc(); + sect_geninfo[0].info.ef = 0; + sect_geninfo[0].exDataSize = 0; + } + + if(unlikely(mbuf == NULL)) { + print_err("Alloc fail!\n"); + return (-1); + } + + params.numSections = 1;//nsection; + params.sections = sect_geninfo; + + ret = xran_prepare_ctrl_pkt(mbuf, ¶ms, cc_id, ru_port_id, seq_id); + if(ret < 0) { + print_err("Fail to build control plane packet - [%d:%d:%d] dir=%d\n", + frame_id, subframe_id, slot_id, dir); + } else { + int32_t cp_sent = 0; + int32_t pkt_len = 0; + /* add in the ethernet header */ + struct rte_ether_hdr *const h = (void *)rte_pktmbuf_prepend(mbuf, sizeof(*h)); + pkt_len = rte_pktmbuf_pkt_len(mbuf); + pCnt->tx_counter++; + pCnt->tx_bytes_counter += pkt_len; //rte_pktmbuf_pkt_len(mbuf); + if(pkt_len > p_x_ctx->fh_init.mtu) + rte_panic("section %d: pkt_len = %d maxExtBufSize %d\n", i, pkt_len, pPrbMapElem->bf_weight.maxExtBufSize); + //rte_mbuf_sanity_check(mbuf, 0); + cp_sent = p_x_ctx->send_cpmbuf2ring(mbuf, ETHER_TYPE_ECPRI, vf_id); + if(cp_sent != 1) { + rte_pktmbuf_free(mbuf); + } + xran_cp_add_section_info(pHandle, dir, cc_id, ru_port_id, ctx_id, §_geninfo[0].info); + } + } /* for (i=0; ixran_port_id; + } else { + print_err("Invalid pHandle - %p", pHandle); + return (XRAN_STATUS_FAIL); + } + + if(xran_port_id < XRAN_PORTS_NUM) { + if(recvSections[xran_port_id]) { + print_err("Memory already allocated!"); + return (-1); + } + + recvSections[xran_port_id] = malloc(sizeof(struct xran_section_recv_info) * XRAN_MAX_NUM_SECTIONS); + if(recvSections == NULL) { + print_err("Fail to allocate memory!"); + return (-1); + } + + recvCpInfo[xran_port_id].sections = recvSections[xran_port_id]; + } else { + print_err("Incorrect xran port %d\n", xran_port_id); + return (-1); + } + + + return (0); +} + +int32_t +xran_ruemul_release(void *pHandle) +{ + uint16_t xran_port_id; + struct xran_device_ctx* p_dev = NULL; + + if(pHandle) { + p_dev = (struct xran_device_ctx* )pHandle; + xran_port_id = p_dev->xran_port_id; + } else { + print_err("Invalid pHandle - %p", pHandle); + return (XRAN_STATUS_FAIL); + } + + if(xran_port_id < XRAN_PORTS_NUM){ + if(recvSections[xran_port_id]) { + free(recvSections[xran_port_id]); + recvCpInfo[xran_port_id].sections = NULL; + } + } else { + print_err("Incorrect xran port %d\n", xran_port_id); + return (-1); + } + + return (0); +}