/****************************************************************************** * * 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. * *******************************************************************************/ #ifndef _XRAN_COMMON_ #define _XRAN_COMMON_ /** * @brief XRAN layer common functionality for both lls-CU and RU as well as C-plane and * U-plane * @file xran_common.c * @ingroup group_source_xran * @author Intel Corporation **/ #include #include #include #include #include #include "xran_common.h" #include "ethdi.h" #include "xran_pkt.h" #include "xran_pkt_up.h" #include "xran_cp_api.h" #include "xran_up_api.h" #include "../src/xran_printf.h" #ifndef MLOG_ENABLED #include "mlog_lnx_xRAN.h" #else #include "mlog_lnx.h" #endif #define MBUFS_CNT 256 extern int xran_process_rx_sym(void *arg, void *iq_data_start, uint16_t size, uint8_t CC_ID, uint8_t Ant_ID, uint8_t frame_id, uint8_t subframe_id, uint8_t slot_id, uint8_t symb_id); int process_mbuf(struct rte_mbuf *pkt) { void *iq_samp_buf; struct ecpri_seq_id seq; static int symbol_total_bytes = 0; int num_bytes = 0; struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx(); uint8_t CC_ID = 0; uint8_t Ant_ID = 0; uint8_t frame_id = 0; uint8_t subframe_id = 0; uint8_t slot_id = 0; uint8_t symb_id = 0; num_bytes = xran_extract_iq_samples(pkt, &iq_samp_buf, &CC_ID, &Ant_ID, &frame_id, &subframe_id, &slot_id, &symb_id, &seq); if (num_bytes <= 0) return -1; symbol_total_bytes += num_bytes; if (seq.e_bit == 1) { print_dbg("Completed receiving symbol %d, size=%d bytes\n", symb_id, symbol_total_bytes); if (symbol_total_bytes) xran_process_rx_sym(NULL, iq_samp_buf, symbol_total_bytes, CC_ID, Ant_ID, frame_id, subframe_id, slot_id, symb_id); symbol_total_bytes = 0; } return 0; } static int set_iq_bit_width(uint8_t iq_bit_width, struct data_section_compression_hdr *compr_hdr) { if (iq_bit_width == MAX_IQ_BIT_WIDTH) compr_hdr->ud_comp_hdr.ud_iq_width = (uint8_t) 0; else compr_hdr->ud_comp_hdr.ud_iq_width = iq_bit_width; return 0; } /* Send a single 5G symbol over multiple packets */ int send_symbol_ex(enum xran_pkt_dir direction, uint16_t section_id, struct rb_map *data, uint8_t frame_id, uint8_t subframe_id, uint8_t slot_id, uint8_t symbol_no, int prb_start, int prb_num, uint8_t CC_ID, uint8_t RU_Port_ID, uint8_t seq_id) { const int n_bytes = prb_num * N_SC_PER_PRB * sizeof(struct rb_map); int sent; uint32_t off; struct xran_up_pkt_gen_no_compression_params xp = { 0 }; /* radio app header */ xp.app_params.data_direction = direction; xp.app_params.payl_ver = 1; xp.app_params.filter_id = 0; xp.app_params.frame_id = frame_id; xp.app_params.sf_slot_sym.subframe_id = subframe_id; xp.app_params.sf_slot_sym.slot_id = slot_id; xp.app_params.sf_slot_sym.symb_id = symbol_no; /* convert to network byte order */ xp.app_params.sf_slot_sym.value = rte_cpu_to_be_16(xp.app_params.sf_slot_sym.value); xp.sec_hdr.fields.sect_id = section_id; xp.sec_hdr.fields.num_prbu = (uint8_t)prb_num; xp.sec_hdr.fields.start_prbu = (uint8_t)prb_start; xp.sec_hdr.fields.sym_inc = 0; xp.sec_hdr.fields.rb = 0; /* network byte order */ xp.sec_hdr.fields.all_bits = rte_cpu_to_be_32(xp.sec_hdr.fields.all_bits); struct rte_mbuf *mb = xran_ethdi_mbuf_alloc(); if (mb == NULL){ MLogPrint(NULL); errx(1, "out of mbufs after %d packets", 1); } sent = xran_prepare_iq_symbol_portion_no_comp(mb, data, n_bytes, &xp, CC_ID, RU_Port_ID, seq_id); if (sent <= 0) errx(1, "failed preparing symbol"); xran_ethdi_mbuf_send(mb, ETHER_TYPE_ECPRI); #ifdef DEBUG printf("Symbol %2d sent (%d packets, %d bytes)\n", symbol_no, i, n_bytes); #endif return sent; } int send_cpmsg_dlul(void *pHandle, enum xran_pkt_dir dir, uint8_t frame_id, uint8_t subframe_id, uint8_t slot_id, uint8_t startsym, uint8_t numsym, int prb_num, uint16_t beam_id, uint8_t cc_id, uint8_t ru_port_id, uint8_t seq_id) { struct xran_cp_gen_params params; struct xran_section_gen_info sect_geninfo[XRAN_MAX_NUM_SECTIONS]; struct rte_mbuf *mbuf; int ret, nsection, i; params.dir = dir; params.sectionType = XRAN_CP_SECTIONTYPE_1; // Most DL/UL Radio Channels 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; // start Symbol ID params.hdr.iqWidth = xran_get_conf_iqwidth(pHandle); params.hdr.compMeth = xran_get_conf_compmethod(pHandle); nsection = 0; sect_geninfo[nsection].info.type = params.sectionType; sect_geninfo[nsection].info.id = xran_alloc_sectionid(pHandle, dir, cc_id, ru_port_id, slot_id); sect_geninfo[nsection].info.rb = XRAN_RBIND_EVERY; sect_geninfo[nsection].info.symInc = XRAN_SYMBOLNUMBER_NOTINC; sect_geninfo[nsection].info.startPrbc = 0; sect_geninfo[nsection].info.numPrbc = NUM_OF_PRB_IN_FULL_BAND, sect_geninfo[nsection].info.numSymbol = numsym; sect_geninfo[nsection].info.reMask = 0xfff; sect_geninfo[nsection].info.beamId = beam_id; sect_geninfo[nsection].info.ef = 0; // no extension sect_geninfo[nsection].exDataSize = 0; sect_geninfo[nsection].exData = NULL; nsection++; params.numSections = nsection; params.sections = sect_geninfo; mbuf = xran_ethdi_mbuf_alloc(); if(unlikely(mbuf == NULL)) { print_err("Alloc fail!\n"); return (-1); } 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 { xran_ethdi_mbuf_send_cp(mbuf, ETHER_TYPE_ECPRI); for(i=0; iPrachCPConfig); #if 0 printf("%d:%d:%d:%d - filter=%d, startSym=%d[%d:%d], numSym=%d, occasions=%d, freqOff=%d\n", frame_id, subframe_id, slot_id, prach_port_id, pPrachCPConfig->filterIdx, pPrachCPConfig->startSymId, pPrachCPConfig->startPrbc, pPrachCPConfig->numPrbc, pPrachCPConfig->numSymbol, pPrachCPConfig->occassionsInPrachSlot, pPrachCPConfig->freqOffset); #endif params.dir = XRAN_DIR_UL; params.sectionType = XRAN_CP_SECTIONTYPE_3; params.hdr.filterIdx = pPrachCPConfig->filterIdx; params.hdr.frameId = frame_id; params.hdr.subframeId = subframe_id; params.hdr.slotId = slot_id; params.hdr.startSymId = pPrachCPConfig->startSymId; params.hdr.iqWidth = xran_get_conf_iqwidth(pHandle); params.hdr.compMeth = xran_get_conf_compmethod(pHandle); /* use timeOffset field for the CP length value for prach sequence */ params.hdr.timeOffset = pPrachCPConfig->timeOffset; params.hdr.fftSize = xran_get_conf_fftsize(pHandle); params.hdr.scs = xran_get_conf_prach_scs(pHandle); params.hdr.cpLength = 0; nsection = 0; sect_geninfo[nsection].info.type = params.sectionType; sect_geninfo[nsection].info.id = xran_alloc_sectionid(pHandle, XRAN_DIR_UL, cc_id, prach_port_id, slot_id); sect_geninfo[nsection].info.rb = XRAN_RBIND_EVERY; sect_geninfo[nsection].info.symInc = XRAN_SYMBOLNUMBER_NOTINC; sect_geninfo[nsection].info.startPrbc = pPrachCPConfig->startPrbc; sect_geninfo[nsection].info.numPrbc = pPrachCPConfig->numPrbc, sect_geninfo[nsection].info.numSymbol = pPrachCPConfig->numSymbol*pPrachCPConfig->occassionsInPrachSlot; sect_geninfo[nsection].info.reMask = 0xfff; sect_geninfo[nsection].info.beamId = beam_id; sect_geninfo[nsection].info.freqOffset= pPrachCPConfig->freqOffset; sect_geninfo[nsection].info.ef = 0; // no extension sect_geninfo[nsection].exDataSize = 0; sect_geninfo[nsection].exData = NULL; nsection++; params.numSections = nsection; params.sections = sect_geninfo; mbuf = xran_ethdi_mbuf_alloc(); if(unlikely(mbuf == NULL)) { print_err("Alloc fail!\n"); return (-1); } ret = xran_prepare_ctrl_pkt(mbuf, ¶ms, cc_id, prach_port_id, seq_id); if(ret < 0) { print_err("Fail to build prach control packet - [%d:%d:%d]\n", frame_id, subframe_id, slot_id); return (ret); } else { xran_ethdi_mbuf_send_cp(mbuf, ETHER_TYPE_ECPRI); for(i=0; i < nsection; i++) xran_cp_add_section_info(pHandle, XRAN_DIR_UL, cc_id, prach_port_id, subframe_id, slot_id, §_geninfo[i].info); } return (ret); } int process_ring(struct rte_ring *r) { assert(r); struct rte_mbuf *mbufs[MBUFS_CNT]; int i; uint32_t remaining; const uint16_t dequeued = rte_ring_dequeue_burst(r, (void **)mbufs, RTE_DIM(mbufs), &remaining); if (!dequeued) return 0; for (i = 0; i < dequeued; ++i) { if (xran_ethdi_filter_packet(mbufs[i], 0) == MBUF_FREE) rte_pktmbuf_free(mbufs[i]); } return remaining; } int ring_processing_thread(void *args) { struct timespec tv = {0}; int64_t prev_nsec = 0; uint8_t is_timer_set = 0; struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx(); struct sched_param sched_param; int res = 0; printf("%s [CPU %2d] [PID: %6d]\n", __FUNCTION__, rte_lcore_id(), getpid()); sched_param.sched_priority = XRAN_THREAD_DEFAULT_PRIO; if ((res = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sched_param))) { printf("priority is not changed: coreId = %d, result1 = %d\n",rte_lcore_id(), res); } for (;;) { if (!is_timer_set) { if (clock_gettime(CLOCK_REALTIME, &tv) != 0) err(1, "gettimeofday() failed"); if (tv.tv_nsec % 125000 < prev_nsec % 125000) { /* crossed an 125ms boundary */ rte_timer_manage(); /* timers only run on IO core */ is_timer_set = 1; } prev_nsec = tv.tv_nsec; } else { rte_timer_manage(); } /* UP first */ if (process_ring(ctx->rx_ring[ETHDI_UP_VF])) continue; /* CP next */ if (process_ring(ctx->rx_ring[ETHDI_CP_VF])) continue; if (XRAN_STOPPED == xran_if_current_state) break; } puts("Pkt processing thread finished."); return 0; } #endif /* _XRAN_COMMON_ */