From baea11c35c59659cbadf1db34b983fba337c267e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Sun, 8 Oct 2023 18:43:06 +0200 Subject: [PATCH] Add O-RAN 7.2 FHI library - Add the O-RAN 7.2 FHI library, interfacing with OSC xRAN library (E release) - Add Findxran.cmake to detect the library and headers, including version information - Test for numa and DPDK presence - Add patch for OSC xRAN to make interworking possible - Add sample config files for LiteOn, Benetel, and VVDN units. Documentation is provided in the next commit. Co-authored-by: Raymond Knopp Co-authored-by: Cedric Roux Co-authored-by: Manish Kumar Singh Co-authored-by: thamizhselvan.k Co-authored-by: rajeshwari.p Co-authored-by: Hongzhi Wang Co-authored-by: Sofia Pison --- cmake_targets/build_oai | 24 +- cmake_targets/tools/MODULES/Findxran.cmake | 140 +++ .../E/oaioran_E.patch | 443 +++++++++ radio/CMakeLists.txt | 5 + radio/fhi_72/CMakeLists.txt | 31 + radio/fhi_72/oaioran.c | 553 +++++++++++ radio/fhi_72/oaioran.h | 37 + radio/fhi_72/oran-config.c | 886 ++++++++++++++++++ radio/fhi_72/oran-config.h | 40 + radio/fhi_72/oran-init.c | 465 +++++++++ radio/fhi_72/oran-init.h | 63 ++ radio/fhi_72/oran-params.h | 114 +++ radio/fhi_72/oran.h | 40 + radio/fhi_72/oran_isolate.c | 318 +++++++ radio/fhi_72/oran_isolate.h | 53 ++ .../gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf | 311 ++++++ ...sa.band78.273prb.fhi72.4x2-benetel650.conf | 304 ++++++ ...gnb.sa.band78.273prb.fhi72.4x4-liteon.conf | 303 ++++++ 18 files changed, 4123 insertions(+), 7 deletions(-) create mode 100644 cmake_targets/tools/MODULES/Findxran.cmake create mode 100644 cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch create mode 100644 radio/fhi_72/CMakeLists.txt create mode 100644 radio/fhi_72/oaioran.c create mode 100644 radio/fhi_72/oaioran.h create mode 100644 radio/fhi_72/oran-config.c create mode 100644 radio/fhi_72/oran-config.h create mode 100644 radio/fhi_72/oran-init.c create mode 100644 radio/fhi_72/oran-init.h create mode 100644 radio/fhi_72/oran-params.h create mode 100644 radio/fhi_72/oran.h create mode 100644 radio/fhi_72/oran_isolate.c create mode 100644 radio/fhi_72/oran_isolate.h create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 31d54ab9ea..ec8e50a2f8 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -96,7 +96,7 @@ Options: USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, None (Default) Adds this RF board support (in external packages installation and in compilation) -t | --transport - Selects the transport protocol type, options: None, Ethernet, benetel4g, benetel5g + Selects the transport protocol type, options: None, Ethernet, benetel4g, benetel5g, oran_fhlib_5g -P | --phy_simulators Makes the unitary tests Layer 1 simulators -S | --core_simulators @@ -248,7 +248,7 @@ function main() { RU=1 TARGET_LIST="$TARGET_LIST oairu" echo_info "Will compile RRU" - shift;; + shift;; --UE) UE=1 TARGET_LIST="$TARGET_LIST lte-uesoftmodem" @@ -302,10 +302,14 @@ function main() { TARGET_LIST="$TARGET_LIST oai_eth_transpro" CMAKE_CMD="$CMAKE_CMD -DOAI_${2^^}=ON" # ^^ makes uppercase ;; - "benetel4g" | "benetel5g") + "benetel4g" | "benetel5g" | "oran_fhlib_4g") TARGET_LIST="$TARGET_LIST $2" CMAKE_CMD="$CMAKE_CMD -DOAI_${2^^}=ON" # ^^ makes uppercase ;; + "oran_fhlib_5g") + TARGET_LIST="$TARGET_LIST $2" + CMAKE_CMD="$CMAKE_CMD -DOAI_FHI72=ON" + ;; "None") ;; *) @@ -387,7 +391,7 @@ function main() { echo_info "Enabling build of optional shared library $lib" done fi - shift 2;; + shift 2;; --noavx512) CMAKE_CMD="$CMAKE_CMD -DAVX512=OFF" echo_info "Disabling AVX512 instructions" @@ -424,8 +428,8 @@ function main() { -h | --help) print_help exit 1;; - *) - print_help + *) + print_help echo_fatal "Unknown option $1" break;; esac @@ -454,7 +458,7 @@ function main() { if [ ! -v BUILD_UHD_FROM_SOURCE ] && [ ! "$DISABLE_HARDWARE_DEPENDENCY" == "True" ]; then install_usrp_uhd_driver $UHD_IMAGES_DIR fi - fi + fi if [ "$HW" == "OAI_BLADERF" ] ; then echo_info "installing packages for BLADERF support" check_install_bladerf_driver @@ -503,6 +507,12 @@ function main() { echo_info "Built Doxygen based documentation. The documentation file is located here: $OPENAIR_DIR/$BUILD_DIR/build/html/index.html" fi + # TODO: once we got the CMakeLists.txt file done for the ORAN files, remove the following lines + if [[ $TARGET_LIST =~ "oran_fhlib_5g" ]]; then + rm -f liboai_transpro.so + ln -s liboran_fhlib_5g.so liboai_transpro.so + fi + if [ "$UE" = 1 ] ; then echo_info "Compiling UE specific part" diff --git a/cmake_targets/tools/MODULES/Findxran.cmake b/cmake_targets/tools/MODULES/Findxran.cmake new file mode 100644 index 0000000000..1405fd6053 --- /dev/null +++ b/cmake_targets/tools/MODULES/Findxran.cmake @@ -0,0 +1,140 @@ +# +# Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The OpenAirInterface Software Alliance licenses this file to You under +# the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 +# +# 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. +# ------------------------------------------------------------------------------ +# For more information about the OpenAirInterface (OAI) Software Alliance: +# contact@openairinterface.org +# + +# FindXran +# ------- +# +# Finds the xran library. Note that the library number is as follows: +# - oran_bronze_release_v1.1 -> 2.1.1 (B = second letter) +# - oran_e_maintenance_release_v1.0 -> 5.1.0 +# the version is currently hardcoded to 5.1.0 +# +# Required options +# ^^^^^^^^^^^^^^^^ +# +# ``xran_LOCATION`` +# The location of the library. +# +# Imported Targets +# ^^^^^^^^^^^^^^^^ +# +# This module provides the following imported targets, if found: +# +# ``xran::xran`` +# The xran library +# +# Result Variables +# ^^^^^^^^^^^^^^^^ +# +# This will define the following variables: +# +# ``xran_FOUND`` +# True if the system has the xran library. +# ``xran_VERSION`` +# The version of the xran library which was found. +# ``xran_INCLUDE_DIRS`` +# Include directories needed to use xran. +# ``xran_LIBRARIES`` +# Libraries needed to link to xran. +# +# Cache Variables +# ^^^^^^^^^^^^^^^ +# +# The following cache variables may also be set: +# +# ``xran_INCLUDE_DIR`` +# The directory containing ``foo.h``. +# ``xran_LIBRARY`` +# The path to the xran library. + +option(xran_LOCATION "directory of XRAN library" "") +if (NOT xran_LOCATION) + message(FATAL_ERROR "xran_LOCATION required") +endif() +if (NOT EXISTS ${xran_LOCATION}) + message(FATAL_ERROR "no such directory: ${xran_LOCATION}") +endif() + +find_path(xran_INCLUDE_DIR + NAMES + xran_common.h + xran_compression.h + xran_cp_api.h + xran_ecpri_owd_measurements.h + xran_fh_o_du.h + xran_pkt.h + xran_pkt_up.h + xran_sync_api.h + PATHS ${xran_LOCATION} + PATH_SUFFIXES api +) +find_library(xran_LIBRARY + NAMES xran + PATHS ${xran_LOCATION}/build +) +if (NOT xran_LIBRARY) + message(FATAL_ERROR "could not detect xran build artifacts at ${xran_LOCATION}/build") +endif() + +set(xran_VERSION_FILE "${xran_LOCATION}/../app/src/common.h") +if(NOT EXISTS ${xran_VERSION_FILE}) + message(FATAL_ERROR "could not find xran version file at ${xran_VERSION_FILE}") +endif() + +file(STRINGS ${xran_VERSION_FILE} xran_VERSION_LINE REGEX "^#define[ \t]+VERSIONX[ \t]+\"[a-z_.0-9]+\"$") +string(REGEX REPLACE "^#define[ \t]+VERSIONX[ \t]+\"([a-z_.0-9]+)\"$" "\\1" xran_VERSION_STRING "${xran_VERSION_LINE}") +message(STATUS "Found xran release ${xran_VERSION_STRING}") +set(xran_VERSION "NOTFOUND") +if (xran_VERSION_STRING STREQUAL "oran_e_maintenance_release_v1.0") + set(xran_VERSION 5.1.0) +elseif (xran_VERSION_STRING STREQUAL "oran_e_maintenance_release_v1.1") + set(xran_VERSION 5.1.1) +endif() +unset(xran_VERSION_LINE) +unset(xran_VERSION_STRING) +unset(xran_VERSION_FILE) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(xran + FOUND_VAR xran_FOUND + REQUIRED_VARS + xran_LIBRARY + xran_INCLUDE_DIR + VERSION_VAR xran_VERSION +) + +if(xran_FOUND) + set(xran_LIBRARIES ${xran_LIBRARY}) + set(xran_INCLUDE_DIRS ${xran_INCLUDE_DIR}) +endif() + +if(xran_FOUND AND NOT TARGET xran::xran) + add_library(xran::xran UNKNOWN IMPORTED) + set_target_properties(xran::xran PROPERTIES + IMPORTED_LOCATION "${xran_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${xran_INCLUDE_DIR}" + ) +endif() + +mark_as_advanced( + xran_INCLUDE_DIR + xran_LIBRARY +) diff --git a/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch b/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch new file mode 100644 index 0000000000..ef44581240 --- /dev/null +++ b/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch @@ -0,0 +1,443 @@ +diff --git a/fhi_lib/app/src/common.h b/fhi_lib/app/src/common.h +index 7508117..a93c085 100644 +--- a/fhi_lib/app/src/common.h ++++ b/fhi_lib/app/src/common.h +@@ -28,7 +28,7 @@ + #include + #include + +-#define VERSIONX "oran_e_maintenance_release_v1.0" ++#define VERSIONX "oran_e_maintenance_release_v1.1" + + #define APP_O_DU 0 + #define APP_O_RU 1 +diff --git a/fhi_lib/lib/Makefile b/fhi_lib/lib/Makefile +index de141bf..5bcde3d 100644 +--- a/fhi_lib/lib/Makefile ++++ b/fhi_lib/lib/Makefile +@@ -23,11 +23,11 @@ MYCUSTOMSPACE1='------------------------------------------------------------' + ############################################################## + # Tools configuration + ############################################################## +-CC := icc +-CPP := icpc ++CC := gcc ++CPP := g++ + AS := as + AR := ar +-LD := icc ++LD := gcc + OBJDUMP := objdump + + ifeq ($(SHELL),cmd.exe) +@@ -95,8 +95,7 @@ CPP_SRC = $(SRC_DIR)/xran_compression.cpp \ + $(SRC_DIR)/xran_bfp_cplane32.cpp \ + $(SRC_DIR)/xran_bfp_cplane64.cpp \ + $(SRC_DIR)/xran_bfp_uplane_9b16rb.cpp \ +- $(SRC_DIR)/xran_bfp_uplane.cpp \ +- $(SRC_DIR)/xran_mod_compression.cpp ++ $(SRC_DIR)/xran_bfp_uplane.cpp + + CPP_SRC_SNC = $(SRC_DIR)/xran_compression_snc.cpp \ + $(SRC_DIR)/xran_bfp_cplane8_snc.cpp \ +@@ -112,12 +111,12 @@ CC_FLAGS += -std=gnu11 -Wall -Wno-deprecated-declarations \ + -fPIC \ + -Wall \ + -Wimplicit-function-declaration \ +- -g -O3 -wd1786 -mcmodel=large ++ -g -O -mavx512bw -march=skylake-avx512 -mtune=skylake-avx512#--wd1786 -mcmodel=large + +-CPP_FLAGS := -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D_GNU_SOURCE -D_REENTRANT -pipe -no-prec-div \ +- -no-prec-div -fp-model fast=2 -fPIC \ +- -no-prec-sqrt -falign-functions=16 -fast-transcendentals \ +- -Werror -Wno-unused-variable -std=c++14 -mcmodel=large ++CPP_FLAGS := -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D_GNU_SOURCE -D_REENTRANT -pipe \ ++ -fPIC \ ++ -falign-functions=16 \ ++ -Werror -Wno-unused-variable -std=c++14 -mcmodel=large -mavx512bw -march=skylake-avx512 -mtune=skylake-avx512 + + INC := -I$(API_DIR) -I$(ETH_DIR) -I$(SRC_DIR) -I$(RTE_INC) + DEF := +@@ -150,8 +149,8 @@ CPP_SNC_OBJTARGETS := $(addprefix $(PROJECT_OBJ_DIR)/,$(CPP_OBJS_SNC)) + + AS_OBJTARGETS := $(addprefix $(PROJECT_OBJ_DIR)/,$(AS_OBJS)) + #-qopt-report=5 -qopt-matmul -qopt-report-phase=all +-CPP_COMP := -O3 -DNDEBUG -xcore-avx512 -fPIE -restrict -fasm-blocks +-CPP_COMP_SNC := -O3 -DNDEBUG -march=icelake-server -fPIE -restrict -fasm-blocks ++CPP_COMP := -O3 -DNDEBUG -fPIE ++CPP_COMP_SNC := -O3 -DNDEBUG -march=icelake-server -fPIE + CC_FLAGS_FULL := $(CC_FLAGS) $(INC) $(DEF) + CPP_FLAGS_FULL := $(CPP_FLAGS) $(CPP_COMP) $(INC) $(DEF) + CPP_FLAGS_FULL_SNC := $(CPP_FLAGS) $(CPP_COMP_SNC) $(INC) $(DEF) +diff --git a/fhi_lib/lib/api/xran_fh_o_du.h b/fhi_lib/lib/api/xran_fh_o_du.h +index 7419ae1..a85f973 100644 +--- a/fhi_lib/lib/api/xran_fh_o_du.h ++++ b/fhi_lib/lib/api/xran_fh_o_du.h +@@ -1104,6 +1104,30 @@ int32_t xran_reg_physide_cb(void *pHandle, xran_fh_tti_callback_fn Cb, void *cbP + */ + int32_t xran_get_slot_idx (uint32_t PortId, uint32_t *nFrameIdx, uint32_t *nSubframeIdx, uint32_t *nSlotIdx, uint64_t *nSecond); + ++/** ++ * @ingroup xran ++ * ++ * Function returns Frame, Subframe, Slot Number based on rx_tti ++ * ++ * @param tti ++ * tti for which to compute Frame, Subframe, Slot ++ * ++ * @param nFrameIdx ++ * Pointer to Frame number [0-99] ++ * ++ * @param nSubframeIdx ++ * Pointer to Subframe number [0-10] ++ * ++ * @param nSlotIdx ++ * Pointer to Slot number [0-7] ++ * ++ * @param nSecond ++ * Pointer to current UTC second ++ * ++ * @return ++ * current TTI number [0-7999] ++ */ ++int32_t xran_get_slot_idx_from_tti (uint32_t tti, uint32_t *nFrameIdx, uint32_t *nSubframeIdx, uint32_t * nSlotIdx, uint64_t *nSecond); + /** + * @ingroup xran + * +diff --git a/fhi_lib/lib/api/xran_up_api.h b/fhi_lib/lib/api/xran_up_api.h +index 7d3afc5..3e00c5a 100644 +--- a/fhi_lib/lib/api/xran_up_api.h ++++ b/fhi_lib/lib/api/xran_up_api.h +@@ -80,6 +80,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, + uint8_t *subframe_id, + uint8_t *slot_id, + uint8_t *symb_id, ++ uint8_t *filter_id, + union ecpri_seq_id *seq_id, + uint16_t *num_prbu, + uint16_t *start_prbu, +diff --git a/fhi_lib/lib/ethernet/ethdi.c b/fhi_lib/lib/ethernet/ethdi.c +index b6ba257..74b3c26 100644 +--- a/fhi_lib/lib/ethernet/ethdi.c ++++ b/fhi_lib/lib/ethernet/ethdi.c +@@ -479,11 +479,13 @@ xran_ethdi_init_dpdk_io(char *name, const struct xran_io_cfg *io_cfg, + ctx->tx_ring[i] = rte_ring_create(ring_name, NUM_MBUFS_RING_TRX, + rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ); + PANIC_ON(ctx->tx_ring[i] == NULL, "failed to allocate rx ring"); ++ printf("Created ring %s on core %d\n",ring_name,*lcore_id); + for(qi = 0; qi < io_cfg->num_rxq; qi++) { + snprintf(ring_name, RTE_DIM(ring_name), "%s_%d_%d", "rx_ring_cp", i, qi); + ctx->rx_ring[i][qi] = rte_ring_create(ring_name, NUM_MBUFS_RING_TRX, + rte_lcore_to_socket_id(*lcore_id), RING_F_SP_ENQ); + PANIC_ON(ctx->rx_ring[i][qi] == NULL, "failed to allocate rx ring"); ++ printf("Created ring %s on core %d\n",ring_name,*lcore_id); + } + } + } else { +@@ -553,7 +555,7 @@ xran_ethdi_init_dpdk_io(char *name, const struct xran_io_cfg *io_cfg, + ctx->up_dl_pkt_gen_ring[i] = rte_ring_create(ring_name, NUM_MBUFS_RING, + rte_lcore_to_socket_id(*lcore_id), /*RING_F_SC_DEQ*/0); + PANIC_ON(ctx->up_dl_pkt_gen_ring[i] == NULL, "failed to allocate dl gen ring"); +- printf("created %s\n", ring_name); ++ printf("created %s on core %d\n", ring_name, *lcore_id); + } + + return 1; +diff --git a/fhi_lib/lib/src/xran_bfp_ref.cpp b/fhi_lib/lib/src/xran_bfp_ref.cpp +index e6d3067..8e0abee 100644 +--- a/fhi_lib/lib/src/xran_bfp_ref.cpp ++++ b/fhi_lib/lib/src/xran_bfp_ref.cpp +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + static int16_t saturateAbs(int16_t inVal) + { +diff --git a/fhi_lib/lib/src/xran_bfp_uplane.cpp b/fhi_lib/lib/src/xran_bfp_uplane.cpp +index a345df4..7831fa0 100644 +--- a/fhi_lib/lib/src/xran_bfp_uplane.cpp ++++ b/fhi_lib/lib/src/xran_bfp_uplane.cpp +@@ -116,7 +116,7 @@ namespace BFP_UPlane + /// Get AVX512 pointer aligned to desired RB + const __m512i* rawDataIn = reinterpret_cast(dataIn.dataExpanded + numREOffset); + /// Apply the exponent shift +- const auto compData = _mm512_srai_epi16(*rawDataIn, thisExp); ++ const auto compData = _mm512_srai_epi16(_mm512_loadu_epi16(rawDataIn), thisExp); + /// Pack compressed data network byte order + const auto compDataBytePacked = networkBytePack(compData); + /// Store exponent first +@@ -201,7 +201,7 @@ namespace BFP_UPlane + /// Get AVX512 pointer aligned to desired RB + const __m512i* rawDataIn = reinterpret_cast(dataIn.dataExpanded + numREOffset); + /// Apply the exponent shift +- const auto compData = _mm512_srai_epi16(*rawDataIn, thisExp); ++ const auto compData = _mm512_srai_epi16(_mm512_loadu_epi16(rawDataIn), thisExp); + /// Store exponent first + dataOut->dataCompressed[thisRBExpAddr] = thisExp; + /// Now have 1 RB worth of bytes separated into 3 chunks (1 per lane) +diff --git a/fhi_lib/lib/src/xran_common.c b/fhi_lib/lib/src/xran_common.c +index baa673f..edd4ecb 100644 +--- a/fhi_lib/lib/src/xran_common.c ++++ b/fhi_lib/lib/src/xran_common.c +@@ -656,6 +656,7 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid) + int32_t valid_res = 0; + int expect_comp = (p_dev_ctx->fh_cfg.ru_conf.compMeth != XRAN_COMPMETHOD_NONE); + enum xran_comp_hdr_type staticComp = p_dev_ctx->fh_cfg.ru_conf.xranCompHdrType; ++ uint8_t filter_id; + + if (staticComp == XRAN_COMP_HDR_TYPE_STATIC) + { +@@ -674,6 +675,7 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid) + &subframe_id, + &slot_id, + &symb_id, ++ &filter_id, + &seq, + &num_prbu, + &start_prbu, +@@ -688,23 +690,9 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid) + print_err("num_bytes is wrong [%d]\n", num_bytes); + return MBUF_FREE; + } +- +- valid_res = xran_pkt_validate(p_dev_ctx, +- pkt, +- iq_samp_buf, +- num_bytes, +- CC_ID, +- Ant_ID, +- frame_id, +- subframe_id, +- slot_id, +- symb_id, +- &seq, +- num_prbu, +- start_prbu, +- sym_inc, +- rb, +- sect_id); ++ pCnt->rx_counter++; ++ pCnt->Rx_on_time++; ++ pCnt->Total_msgs_rcvd++; + #ifndef FCN_ADAPT + if(valid_res != 0) { + print_dbg("valid_res is wrong [%d] ant %u (%u : %u : %u : %u) seq %u num_bytes %d\n", valid_res, Ant_ID, frame_id, subframe_id, slot_id, symb_id, seq.seq_id, num_bytes); +@@ -1189,7 +1177,7 @@ int generate_cpmsg_prach(void *pHandle, struct xran_cp_gen_params *params, struc + timeOffset += startSymId * (2048 + 144); + } + timeOffset = timeOffset >> nNumerology; //original number is Tc, convert to Ts based on mu +- if ((slot_id == 0) || (slot_id == (SLOTNUM_PER_SUBFRAME(pxran_lib_ctx->interval_us_local) >> 1))) ++ if (startSymId > 0 && ((slot_id == 0) || (slot_id == (SLOTNUM_PER_SUBFRAME(pxran_lib_ctx->interval_us_local) >> 1)))) + timeOffset += 16; + + params->dir = XRAN_DIR_UL; +@@ -1295,8 +1283,7 @@ int32_t ring_processing_func(void* args) + + for (i = 0; i < ctx->io_cfg.num_vfs && i < XRAN_VF_MAX; i++){ + for(qi = 0; qi < ctx->rxq_per_port[i]; qi++) { +- if (process_ring(ctx->rx_ring[i][qi], i, qi)) +- return 0; ++ process_ring(ctx->rx_ring[i][qi],i,qi); + } + } + +diff --git a/fhi_lib/lib/src/xran_common.h b/fhi_lib/lib/src/xran_common.h +index 3ed75cd..d61fe7f 100644 +--- a/fhi_lib/lib/src/xran_common.h ++++ b/fhi_lib/lib/src/xran_common.h +@@ -221,7 +221,7 @@ int generate_cpmsg_prach(void *pHandle, struct xran_cp_gen_params *params, struc + struct xran_eaxcid_config *xran_get_conf_eAxC(void *pHandle); + int xran_register_cb_mbuf2ring(xran_ethdi_mbuf_send_fn mbuf_send_cp, xran_ethdi_mbuf_send_fn mbuf_send_up); + +-uint16_t xran_alloc_sectionid(void *pHandle, uint8_t dir, uint8_t cc_id, uint8_t ant_id, uint8_t slot_id); ++//uint16_t xran_alloc_sectionid(void *pHandle, uint8_t dir, uint8_t cc_id, uint8_t ant_id, uint8_t slot_id); + uint8_t xran_get_seqid(void *pHandle, uint8_t dir, uint8_t cc_id, uint8_t ant_id, uint8_t slot_id); + int32_t ring_processing_func(void* arg); + int xran_init_prach(struct xran_fh_config* pConf, struct xran_device_ctx * p_xran_dev_ctx); +diff --git a/fhi_lib/lib/src/xran_compression.cpp b/fhi_lib/lib/src/xran_compression.cpp +index 112caae..7c74342 100644 +--- a/fhi_lib/lib/src/xran_compression.cpp ++++ b/fhi_lib/lib/src/xran_compression.cpp +@@ -62,7 +62,7 @@ xranlib_compress(const struct xranlib_compress_request *request, + return xranlib_5gnr_mod_compression(&mod_request, &mod_response); + } + else{ +- if(_may_i_use_cpu_feature(_FEATURE_AVX512IFMA52)) { ++ if(false) { + return xranlib_compress_avxsnc(request,response); + } else { + return xranlib_compress_avx512(request,response); +@@ -89,7 +89,7 @@ xranlib_decompress(const struct xranlib_decompress_request *request, + return xranlib_5gnr_mod_decompression(&mod_request, &mod_response); + } + else{ +- if(_may_i_use_cpu_feature(_FEATURE_AVX512IFMA52)) { ++ if(false) { + return xranlib_decompress_avxsnc(request,response); + } else { + return xranlib_decompress_avx512(request,response); +@@ -101,7 +101,7 @@ int32_t + xranlib_compress_bfw(const struct xranlib_compress_request *request, + struct xranlib_compress_response *response) + { +- if(_may_i_use_cpu_feature(_FEATURE_AVX512IFMA52)) { ++ if(false) { + return xranlib_compress_avxsnc_bfw(request,response); + } else { + return xranlib_compress_avx512_bfw(request,response); +@@ -112,7 +112,7 @@ int32_t + xranlib_decompress_bfw(const struct xranlib_decompress_request *request, + struct xranlib_decompress_response *response) + { +- if(_may_i_use_cpu_feature(_FEATURE_AVX512IFMA52)) { ++ if(false) { + return xranlib_decompress_avxsnc_bfw(request,response); + } else { + return xranlib_decompress_avx512_bfw(request,response); +diff --git a/fhi_lib/lib/src/xran_main.c b/fhi_lib/lib/src/xran_main.c +index 89dcc1f..640f6b6 100644 +--- a/fhi_lib/lib/src/xran_main.c ++++ b/fhi_lib/lib/src/xran_main.c +@@ -272,7 +272,7 @@ xran_init_prach(struct xran_fh_config* pConf, struct xran_device_ctx * p_xran_de + printf("PRACH start symbol %u lastsymbol %u\n", p_xran_dev_ctx->prach_start_symbol[0], p_xran_dev_ctx->prach_last_symbol[0]); + } + +- pPrachCPConfig->eAxC_offset = xran_get_num_eAxc(p_xran_dev_ctx); ++ pPrachCPConfig->eAxC_offset = pPRACHConfig->eAxC_offset; + print_dbg("PRACH eAxC_offset %d\n", pPrachCPConfig->eAxC_offset); + + /* Save some configs for app */ +@@ -844,7 +844,7 @@ tx_cp_ul_cb(struct rte_timer *tim, void *arg) + struct xran_cp_gen_params params; + struct xran_section_gen_info sect_geninfo[8]; + struct rte_mbuf *mbuf = xran_ethdi_mbuf_alloc(); +- prach_port_id = ant_id + num_eAxc; ++ prach_port_id = ant_id + pPrachCPConfig->eAxC_offset; + /* start new section information list */ + xran_cp_reset_section_info(pHandle, XRAN_DIR_UL, cc_id, prach_port_id, ctx_id); + +@@ -1059,6 +1059,7 @@ int32_t handle_ecpri_ethertype(struct rte_mbuf* pkt_q[], uint16_t xport_id, stru + { + case ECPRI_IQ_DATA: + pkt_data[num_data++] = pkt; ++ uint8_t *pkt_bytes=rte_pktmbuf_mtod(pkt,uint8_t*); + break; + // For RU emulation + case ECPRI_RT_CONTROL_DATA: +@@ -1076,7 +1077,7 @@ int32_t handle_ecpri_ethertype(struct rte_mbuf* pkt_q[], uint16_t xport_id, stru + break; + default: + if (p_dev_ctx->fh_init.io_cfg.id == O_DU) { +- print_err("Invalid eCPRI message type - %d", ecpri_hdr->cmnhdr.bits.ecpri_mesg_type); ++ rte_pktmbuf_free(pkt); + } + break; + } +@@ -1771,8 +1772,7 @@ ring_processing_func_per_port(void* args) + for (i = 0; i < ctx->io_cfg.num_vfs && i < XRAN_VF_MAX; i = i+1) { + if (ctx->vf2xran_port[i] == port_id) { + for(qi = 0; qi < ctx->rxq_per_port[port_id]; qi++){ +- if (process_ring(ctx->rx_ring[i][qi], i, qi)) +- return 0; ++ process_ring(ctx->rx_ring[i][qi],i,qi); + } + } + } +@@ -1837,8 +1837,6 @@ xran_spawn_workers(void) + nWorkerCore = nWorkerCore << 1; + } + +- extern int _may_i_use_cpu_feature(unsigned __int64); +- icx_cpu = _may_i_use_cpu_feature(_FEATURE_AVX512IFMA52); + + printf("O-XU %d\n", eth_ctx->io_cfg.id); + printf("HW %d\n", icx_cpu); +@@ -3074,6 +3072,24 @@ xran_get_slot_idx (uint32_t PortId, uint32_t *nFrameIdx, uint32_t *nSubframeIdx, + return tti; + } + ++int32_t ++xran_get_slot_idx_from_tti (uint32_t tti, uint32_t *nFrameIdx, uint32_t *nSubframeIdx, uint32_t *nSlotIdx, uint64_t *nSecond) ++{ ++ struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx_by_id(0); ++ if (!p_xran_dev_ctx) ++ { ++ print_err("Null xRAN context on port id %u!!\n", 0); ++ return 0; ++ } ++ ++ *nSlotIdx = (uint32_t)XranGetSlotNum(tti, SLOTNUM_PER_SUBFRAME(p_xran_dev_ctx->interval_us_local)); ++ *nSubframeIdx = (uint32_t)XranGetSubFrameNum(tti,SLOTNUM_PER_SUBFRAME(p_xran_dev_ctx->interval_us_local), SUBFRAMES_PER_SYSTEMFRAME); ++ *nFrameIdx = (uint32_t)XranGetFrameNum(tti,0/*xran_getSfnSecStart()*/,SUBFRAMES_PER_SYSTEMFRAME, SLOTNUM_PER_SUBFRAME(p_xran_dev_ctx->interval_us_local)); ++ *nSecond = timing_get_current_second(); ++ ++ return tti; ++} ++ + int32_t + xran_set_debug_stop(int32_t value, int32_t count) + { +diff --git a/fhi_lib/lib/src/xran_mod_compression.cpp b/fhi_lib/lib/src/xran_mod_compression.cpp +index 7d4a5d0..87bdbd5 100644 +--- a/fhi_lib/lib/src/xran_mod_compression.cpp ++++ b/fhi_lib/lib/src/xran_mod_compression.cpp +@@ -747,10 +747,11 @@ int xranlib_5gnr_mod_compression(const struct xranlib_5gnr_mod_compression_reque + #ifdef C_Module_Used + return (xranlib_5gnr_mod_compression_c(request, response)); + #else +- if(_may_i_use_cpu_feature(_FEATURE_AVX512IFMA52)) ++ if (false) { + return (xranlib_5gnr_mod_compression_snc(request, response)); +- else ++ } else { + return (xranlib_5gnr_mod_compression_avx512(request, response)); ++ } + #endif + } + +diff --git a/fhi_lib/lib/src/xran_rx_proc.c b/fhi_lib/lib/src/xran_rx_proc.c +index 36bd72c..f7f5678 100644 +--- a/fhi_lib/lib/src/xran_rx_proc.c ++++ b/fhi_lib/lib/src/xran_rx_proc.c +@@ -107,6 +107,10 @@ int xran_process_prach_sym(void *arg, + if(mb) + rte_pktmbuf_free(mb); + ++ mb = p_xran_dev_ctx->sFHPrachRxBbuIoBufCtrlDecomp[tti % XRAN_N_FE_BUF_LEN][CC_ID][Ant_ID].sBufferList.pBuffers[symb_id_offset].pCtrl; ++ if(mb) ++ rte_pktmbuf_free(mb); ++ + if(p_xran_dev_ctx->fh_cfg.ru_conf.byteOrder == XRAN_CPU_LE_BYTE_ORDER) { + int idx = 0; + uint16_t *psrc = (uint16_t *)iq_data_start; +diff --git a/fhi_lib/lib/src/xran_up_api.c b/fhi_lib/lib/src/xran_up_api.c +index 397853a..4a714b5 100644 +--- a/fhi_lib/lib/src/xran_up_api.c ++++ b/fhi_lib/lib/src/xran_up_api.c +@@ -329,6 +329,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, + uint8_t *subframe_id, + uint8_t *slot_id, + uint8_t *symb_id, ++ uint8_t *filter_id, + union ecpri_seq_id *seq_id, + uint16_t *num_prbu, + uint16_t *start_prbu, +@@ -387,6 +388,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, + if (symb_id) + *symb_id = radio_hdr->sf_slot_sym.symb_id; + ++ if (filter_id) ++ *filter_id = radio_hdr->data_feature.filter_id; + /* Process data section hdr */ + struct data_section_hdr *data_hdr = + (void *)rte_pktmbuf_adj(mbuf, sizeof(*radio_hdr)); +@@ -401,6 +404,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, + *sym_inc = data_hdr->fields.sym_inc; + *rb = data_hdr->fields.rb; + *sect_id = data_hdr->fields.sect_id; ++ if (*num_prbu == 0) *num_prbu=273; + + if(expect_comp) { + const struct data_section_compression_hdr *data_compr_hdr; diff --git a/radio/CMakeLists.txt b/radio/CMakeLists.txt index 937d8039f9..fb9086e2eb 100644 --- a/radio/CMakeLists.txt +++ b/radio/CMakeLists.txt @@ -13,6 +13,11 @@ if(OAI_BLADERF) add_subdirectory(BLADERF) endif() +add_boolean_option(OAI_FHI72 OFF "Activate OAI's FHI 7.2 (xran/fhi_lib) driver" OFF) +if(OAI_FHI72) + add_subdirectory(fhi_72) +endif() + add_boolean_option(OAI_IRIS OFF "Activate OAI's IRIS/SoapySDR driver" OFF) if(OAI_IRIS) add_subdirectory(IRIS) diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt new file mode 100644 index 0000000000..05cc50b486 --- /dev/null +++ b/radio/fhi_72/CMakeLists.txt @@ -0,0 +1,31 @@ +# use env var PKG_CONFIG_PATH to override paths to libdpdk.pc +pkg_check_modules(dpdk REQUIRED libdpdk) +pkg_check_modules(numa REQUIRED numa) + +find_package(xran 5.1.1 EXACT REQUIRED) # E release -> 5 + +# Ignore xran-specific warning: we don't care/can't change the following warning, so suppress +# alignment 1 of 'struct XYZ' is less than 2 +add_compile_options(-Wno-packed-not-aligned) + +add_library(oran_fhlib_5g MODULE + oran_isolate.c + oaioran.c + oran-config.c + oran-init.c +) + +set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native") +target_link_libraries(oran_fhlib_5g PRIVATE xran::xran) +target_link_libraries(oran_fhlib_5g PRIVATE ${dpdk_LINK_LIBRARIES}) +target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS}) +target_link_libraries(oran_fhlib_5g PRIVATE pthread dl rt m numa) +target_link_libraries(oran_fhlib_5g PRIVATE ${T_LIB}) + +# TODO: can be removed? +target_include_directories(oran_fhlib_5g PRIVATE ${xran_INCLUDE_DIRS}/../src/) + +set_target_properties(oran_fhlib_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +add_custom_command(TARGET oran_fhlib_5g POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g.so liboai_transpro.so + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c new file mode 100644 index 0000000000..fc756e1018 --- /dev/null +++ b/radio/fhi_72/oaioran.c @@ -0,0 +1,553 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include +#include +#include +#include "xran_fh_o_du.h" +#include "xran_compression.h" + +// xran_cp_api.h uses SIMD, but does not include it +#include +#include "xran_cp_api.h" +#include "xran_sync_api.h" +#include "oran_isolate.h" +#include "oran-init.h" +#include "xran_common.h" +#include "oaioran.h" +#include + +#include "oran-config.h" // for g_kbar + +#define USE_POLLING 1 +// Declare variable useful for the send buffer function +volatile uint8_t first_call_set = 0; +volatile uint8_t first_rx_set = 0; +volatile int first_read_set = 0; + +// Variable declaration useful for fill IQ samples from file +#define IQ_PLAYBACK_BUFFER_BYTES (XRAN_NUM_OF_SLOT_IN_TDD_LOOP * N_SYM_PER_SLOT * XRAN_MAX_PRBS * N_SC_PER_PRB * 4L) +/* +int rx_tti; +int rx_sym; +volatile uint32_t rx_cb_tti = 0; +volatile uint32_t rx_cb_frame = 0; +volatile uint32_t rx_cb_subframe = 0; +volatile uint32_t rx_cb_slot = 0; +*/ + +#define GetFrameNum(tti, SFNatSecStart, numSubFramePerSystemFrame, numSlotPerSubFrame) \ + ((((uint32_t)tti / ((uint32_t)numSubFramePerSystemFrame * (uint32_t)numSlotPerSubFrame)) + SFNatSecStart) & 0x3FF) +#define GetSlotNum(tti, numSlotPerSfn) ((uint32_t)tti % ((uint32_t)numSlotPerSfn)) + +int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id); +#include "common/utils/LOG/log.h" + +#ifndef USE_POLLING +extern notifiedFIFO_t oran_sync_fifo; +#else +volatile oran_sync_info_t oran_sync_info; +#endif +void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) +{ + struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag; + uint64_t second; + uint32_t tti; + uint32_t frame; + uint32_t subframe; + uint32_t slot, slot2; + uint32_t rx_sym; + + static int32_t last_slot = -1; + static int32_t last_frame = -1; + struct xran_device_ctx *xran_ctx = xran_dev_get_ctx(); + const struct xran_fh_init *fh_init = &xran_ctx->fh_init; + int num_ports = fh_init->xran_ports; + static int rx_RU[XRAN_PORTS_NUM][20] = {0}; + uint32_t rx_tti = callback_tag->slotiId; + + tti = xran_get_slot_idx_from_tti(rx_tti, &frame, &subframe, &slot, &second); + + rx_sym = callback_tag->symbol; + uint32_t ru_id = callback_tag->oXuId; + if (rx_sym == 7) { + if (first_call_set) { + if (!first_rx_set) { + LOG_I(NR_PHY, "first_rx is set (num_ports %d)\n", num_ports); + } + first_rx_set = 1; + if (first_read_set == 1) { + slot2 = slot + (subframe << 1); + rx_RU[ru_id][slot2] = 1; + if (last_frame > 0 && frame > 0 + && ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023)))) + LOG_E(PHY, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2); + for (int i = 0; i < num_ports; i++) { + if (rx_RU[i][slot2] == 0) + return; + } + for (int i = 0; i < num_ports; i++) + rx_RU[i][slot2] = 0; + + if (last_slot == -1 || slot2 != last_slot) { +#ifndef USE_POLLING + notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(oran_sync_info_t), 0, &oran_sync_fifo, NULL); + oran_sync_info_t *info = (oran_sync_info_t *)NotifiedFifoData(req); + info->sl = slot2; + info->f = frame; + LOG_D(PHY, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); +#else + LOG_D(PHY, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); + oran_sync_info.tti = tti; + oran_sync_info.sl = slot2; + oran_sync_info.f = frame; +#endif +#ifndef USE_POLLING + pushNotifiedFIFO(&oran_sync_fifo, req); +#else +#endif + } else + LOG_E(PHY, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); + last_slot = slot2; + last_frame = frame; + } // first_read_set == 1 + } // first_call_set + } // rx_sym == 7 +} +void oai_xran_fh_srs_callback(void *pCallbackTag, xran_status_t status) +{ + rte_pause(); +} +void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status) +{ + rte_pause(); +} + +int oai_physide_dl_tti_call_back(void *param) +{ + if (!first_call_set) + printf("first_call set from phy cb first_call_set=%p\n", &first_call_set); + first_call_set = 1; + return 0; +} + +int oai_physide_ul_half_slot_call_back(void *param) +{ + rte_pause(); + return 0; +} + +int oai_physide_ul_full_slot_call_back(void *param) +{ + rte_pause(); + return 0; +} + +int read_prach_data(ru_info_t *ru, int frame, int slot) +{ + /* calculate tti and subframe_id from frame, slot num */ + int tti = 20 * (frame) + (slot); + uint32_t subframe = XranGetSubFrameNum(tti, 2, 10); + uint32_t is_prach_slot = xran_is_prach_slot(0, subframe, (slot % 2)); + int sym_idx = 0; + + struct xran_device_ctx *xran_ctx = xran_dev_get_ctx(); + struct xran_prach_cp_config *pPrachCPConfig = &(xran_ctx->PrachCPConfig); + struct xran_ru_config *ru_conf = &(xran_ctx->fh_cfg.ru_conf); + + int nb_rx_per_ru = ru->nb_rx / xran_ctx->fh_init.xran_ports; + /* If it is PRACH slot, copy prach IQ from XRAN PRACH buffer to OAI PRACH buffer */ + if (is_prach_slot) { + for (sym_idx = 0; sym_idx < pPrachCPConfig->numSymbol; sym_idx++) { + for (int aa = 0; aa < ru->nb_rx; aa++) { + int16_t *dst, *src; + int idx = 0; + xran_ctx = xran_dev_get_ctx_by_id(aa / nb_rx_per_ru); + dst = ru->prach_buf[aa]; // + (sym_idx*576)); + src = (int16_t *)((uint8_t *)xran_ctx->sFHPrachRxBbuIoBufCtrlDecomp[tti % XRAN_N_FE_BUF_LEN][0][aa % nb_rx_per_ru] + .sBufferList.pBuffers[sym_idx] + .pData); + + /* convert Network order to host order */ + if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) { + if (sym_idx == 0) { + for (idx = 0; idx < 139 * 2; idx++) { + dst[idx] = ((int16_t)ntohs(src[idx + g_kbar])); + } + } else { + for (idx = 0; idx < 139 * 2; idx++) { + dst[idx] += ((int16_t)ntohs(src[idx + g_kbar])); + } + } + } else if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_BLKFLOAT) { + struct xranlib_decompress_request bfp_decom_req; + struct xranlib_decompress_response bfp_decom_rsp; + + int16_t local_dst[12 * 2 * N_SC_PER_PRB] __attribute__((aligned(64))); + + int payload_len = (3 * ru_conf->iqWidth_PRACH + 1) * 12; // 12 = closest number of PRBs to 139 REs + + memset(&bfp_decom_req, 0, sizeof(struct xranlib_decompress_request)); + memset(&bfp_decom_rsp, 0, sizeof(struct xranlib_decompress_response)); + + bfp_decom_req.data_in = (int8_t *)src; + bfp_decom_req.numRBs = 12; // closest number of PRBs to 139 REs + bfp_decom_req.len = payload_len; + bfp_decom_req.compMethod = XRAN_COMPMETHOD_BLKFLOAT; + bfp_decom_req.iqWidth = ru_conf->iqWidth_PRACH; + + bfp_decom_rsp.data_out = (int16_t *)local_dst; + bfp_decom_rsp.len = 0; + xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp); + // note: this is hardwired for 139 point PRACH sequence, kbar=2 + if (sym_idx == 0) // + for (idx = 0; idx < (139 * 2); idx++) + dst[idx] = local_dst[idx + g_kbar]; + else + for (idx = 0; idx < (139 * 2); idx++) + dst[idx] += (local_dst[idx + g_kbar]); + } // COMPMETHOD_BLKFLOAT + } // aa + } // symb_indx + } // is_prach_slot + return (0); +} + +int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) +{ + void *ptr = NULL; + int32_t *pos = NULL; + int idx = 0; + static int last_slot = -1; + first_read_set = 1; + + static int64_t old_rx_counter[XRAN_PORTS_NUM] = {0}; + static int64_t old_tx_counter[XRAN_PORTS_NUM] = {0}; + struct xran_common_counters x_counters[XRAN_PORTS_NUM]; + static int outcnt = 0; +#ifndef USE_POLLING + // pull next even from oran_sync_fifo + notifiedFIFO_elt_t *res = pollNotifiedFIFO(&oran_sync_fifo); + while (res == NULL) { + res = pollNotifiedFIFO(&oran_sync_fifo); + } + oran_sync_info_t *info = (oran_sync_info_t *)NotifiedFifoData(res); + + *slot = info->sl; + *frame = info->f; + delNotifiedFIFO_elt(res); +#else + LOG_D(PHY, "In xran_fh_rx_read_slot, first_rx_set %d\n", first_rx_set); + while (first_rx_set == 0) { + } + + *slot = oran_sync_info.sl; + *frame = oran_sync_info.f; + uint32_t tti_in = oran_sync_info.tti; + + LOG_D(PHY, "oran slot %d, last_slot %d\n", *slot, last_slot); + int cnt = 0; + // while (*slot == last_slot) { + while (tti_in == oran_sync_info.tti) { + //*slot = oran_sync_info.sl; + cnt++; + } + LOG_D(PHY, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot); + last_slot = *slot; +#endif + // return(0); + + int tti = (*frame * 20) + *slot; + + read_prach_data(ru, *frame, *slot); + + struct xran_device_ctx *xran_ctx = xran_dev_get_ctx(); + const struct xran_fh_init *fh_init = &xran_ctx->fh_init; + int nPRBs = xran_ctx->fh_cfg.nULRBs; + int fftsize = 1 << xran_ctx->fh_cfg.ru_conf.fftSize; + + int slot_offset_rxdata = 3 & (*slot); + uint32_t slot_size = 4 * 14 * 4096; + uint8_t *rx_data = (uint8_t *)ru->rxdataF[0]; + uint8_t *start_ptr = NULL; + int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports; + for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet. + for (uint8_t ant_id = 0; ant_id < ru->nb_rx; ant_id++) { + rx_data = (uint8_t *)ru->rxdataF[ant_id]; + start_ptr = rx_data + (slot_size * slot_offset_rxdata); + xran_ctx = xran_dev_get_ctx_by_id(ant_id / nb_rx_per_ru); + const struct xran_fh_config *fh_config = &xran_ctx->fh_cfg; + int tdd_period = fh_config->frame_conf.nTddPeriod; + int slot_in_period = *slot % tdd_period; + if (fh_config->frame_conf.sSlotConfig[slot_in_period].nSymbolType[XRAN_NUM_OF_SYMBOL_PER_SLOT - 1] == 0) + continue; + // skip processing this slot if the last symbol in the slot is TX + // (no RX in this slot) + // This loop would better be more inner to avoid confusion and maybe also errors. + for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) { + /* the callback is for mixed and UL slots. In mixed, we have to + * skip DL and guard symbols. */ + if (fh_config->frame_conf.sSlotConfig[slot_in_period].nSymbolType[sym_idx] != 1 /* UL */) + continue; + + uint8_t *pData; + uint8_t *pPrbMapData = xran_ctx->sFrontHaulRxPrbMapBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_rx_per_ru] + .sBufferList.pBuffers->pData; + struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData; + + struct xran_prb_elm *pRbElm = &pPrbMap->prbMap[0]; + struct xran_section_desc *p_sec_desc = pRbElm->p_sec_desc[sym_idx][0]; + uint32_t one_rb_size = + (((pRbElm->iqWidth == 0) || (pRbElm->iqWidth == 16)) ? (N_SC_PER_PRB * 2 * 2) : (3 * pRbElm->iqWidth + 1)); + if (fh_init->mtu < pRbElm->nRBSize * one_rb_size) + pData = xran_ctx->sFrontHaulRxBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_rx_per_ru] + .sBufferList.pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT] + .pData; + else + pData = p_sec_desc->pData; + ptr = pData; + pos = (int32_t *)(start_ptr + (4 * sym_idx * 4096)); + + uint8_t *u8dptr; + struct xran_prb_map *pRbMap = pPrbMap; + AssertFatal(ptr != NULL, "ptr NULL\n"); + AssertFatal(pos != NULL, "pos NULL\n"); + if (1) { + uint32_t idxElm = 0; + u8dptr = (uint8_t *)ptr; + int16_t payload_len = 0; + + uint8_t *src = (uint8_t *)u8dptr; + + LOG_D(PHY, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm); + for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) { + LOG_D(PHY, + "prbMap[%d] : PRBstart %d nPRBs %d\n", + idxElm, + pRbMap->prbMap[idxElm].nRBStart, + pRbMap->prbMap[idxElm].nRBSize); + pRbElm = &pRbMap->prbMap[idxElm]; + int pos_len = 0; + int neg_len = 0; + + if (pRbElm->nRBStart < (nPRBs >> 1)) // there are PRBs left of DC + neg_len = min((nPRBs * 6) - (pRbElm->nRBStart * 12), pRbElm->nRBSize * N_SC_PER_PRB); + pos_len = (pRbElm->nRBSize * N_SC_PER_PRB) - neg_len; + + src = pData; + // Calculation of the pointer for the section in the buffer. + // positive half + uint8_t *dst1 = (uint8_t *)(pos + (neg_len == 0 ? ((pRbElm->nRBStart * N_SC_PER_PRB) - (nPRBs * 6)) : 0)); + // negative half + uint8_t *dst2 = (uint8_t *)(pos + (pRbElm->nRBStart * N_SC_PER_PRB) + fftsize - (nPRBs * 6)); + int32_t local_dst[pRbElm->nRBSize * N_SC_PER_PRB] __attribute__((aligned(64))); + if (pRbElm->compMethod == XRAN_COMPMETHOD_NONE) { + // NOTE: gcc 11 knows how to generate AVX2 for this! + for (idx = 0; idx < pRbElm->nRBSize * N_SC_PER_PRB * 2; idx++) + ((int16_t *)local_dst)[idx] = ((int16_t)ntohs(((uint16_t *)src)[idx])) >> 2; + memcpy((void *)dst2, (void *)local_dst, neg_len * 4); + memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4); + } else if (pRbElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) { + struct xranlib_decompress_request bfp_decom_req; + struct xranlib_decompress_response bfp_decom_rsp; + + payload_len = (3 * pRbElm->iqWidth + 1) * pRbElm->nRBSize; + + memset(&bfp_decom_req, 0, sizeof(struct xranlib_decompress_request)); + memset(&bfp_decom_rsp, 0, sizeof(struct xranlib_decompress_response)); + + bfp_decom_req.data_in = (int8_t *)src; + bfp_decom_req.numRBs = pRbElm->nRBSize; + bfp_decom_req.len = payload_len; + bfp_decom_req.compMethod = pRbElm->compMethod; + bfp_decom_req.iqWidth = pRbElm->iqWidth; + + bfp_decom_rsp.data_out = (int16_t *)local_dst; + bfp_decom_rsp.len = 0; + + xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp); + memcpy((void *)dst2, (void *)local_dst, neg_len * 4); + memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4); + outcnt++; + } else { + printf("pRbElm->compMethod == %d is not supported\n", pRbElm->compMethod); + exit(-1); + } + } + + } else { + return 0; + } + } // sym_ind + } // ant_ind + } // vv_inf + if ((*frame & 0x7f) == 0 && *slot == 0 && xran_get_common_counters(gxran_handle, &x_counters[0]) == XRAN_STATUS_SUCCESS) { + for (int o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { + LOG_I(NR_PHY, + "[%s%d][rx %7ld pps %7ld kbps %7ld][tx %7ld pps %7ld kbps %7ld][Total Msgs_Rcvd %ld]\n", + "o-du ", + o_xu_id, + x_counters[o_xu_id].rx_counter, + x_counters[o_xu_id].rx_counter - old_rx_counter[o_xu_id], + x_counters[o_xu_id].rx_bytes_per_sec * 8 / 1000L, + x_counters[o_xu_id].tx_counter, + x_counters[o_xu_id].tx_counter - old_tx_counter[o_xu_id], + x_counters[o_xu_id].tx_bytes_per_sec * 8 / 1000L, + x_counters[o_xu_id].Total_msgs_rcvd); + for (int rxant = 0; rxant < ru->nb_rx / fh_init->xran_ports; rxant++) + LOG_I(NR_PHY, + "[%s%d][pusch%d %7ld prach%d %7ld]\n", + "o_du", + o_xu_id, + rxant, + x_counters[o_xu_id].rx_pusch_packets[rxant], + rxant, + x_counters[o_xu_id].rx_prach_packets[rxant]); + if (x_counters[o_xu_id].rx_counter > old_rx_counter[o_xu_id]) + old_rx_counter[o_xu_id] = x_counters[o_xu_id].rx_counter; + if (x_counters[o_xu_id].tx_counter > old_tx_counter[o_xu_id]) + old_tx_counter[o_xu_id] = x_counters[o_xu_id].tx_counter; + } + } + return (0); +} + +int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) +{ + int tti = /*frame*SUBFRAMES_PER_SYSTEMFRAME*SLOTNUM_PER_SUBFRAME+*/ 20 * frame + + slot; // commented out temporarily to check that compilation of oran 5g is working. + + void *ptr = NULL; + int32_t *pos = NULL; + int idx = 0; + + struct xran_device_ctx *xran_ctx = xran_dev_get_ctx(); + const struct xran_fh_init *fh_init = &xran_ctx->fh_init; + int nPRBs = xran_ctx->fh_cfg.nDLRBs; + int fftsize = 1 << xran_ctx->fh_cfg.ru_conf.fftSize; + int nb_tx_per_ru = ru->nb_tx / fh_init->xran_ports; + + for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet. + for (uint8_t ant_id = 0; ant_id < ru->nb_tx; ant_id++) { + xran_ctx = xran_dev_get_ctx_by_id(ant_id / nb_tx_per_ru); + // This loop would better be more inner to avoid confusion and maybe also errors. + for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) { + uint8_t *pData = xran_ctx->sFrontHaulTxBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_tx_per_ru] + .sBufferList.pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT] + .pData; + uint8_t *pPrbMapData = xran_ctx->sFrontHaulTxPrbMapBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_tx_per_ru] + .sBufferList.pBuffers->pData; + struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData; + ptr = pData; + pos = + &ru->txdataF_BF[ant_id][sym_idx * 4096 /*fp->ofdm_symbol_size*/]; // We had to use a different ru structure than benetel + // so the access to the buffer is not the same. + + uint8_t *u8dptr; + struct xran_prb_map *pRbMap = pPrbMap; + int32_t sym_id = sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT; + if (ptr && pos) { + uint32_t idxElm = 0; + u8dptr = (uint8_t *)ptr; + int16_t payload_len = 0; + + uint8_t *dst = (uint8_t *)u8dptr; + + struct xran_prb_elm *p_prbMapElm = &pRbMap->prbMap[idxElm]; + + for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) { + struct xran_section_desc *p_sec_desc = NULL; + p_prbMapElm = &pRbMap->prbMap[idxElm]; + p_sec_desc = + // assumes one fragment per symbol + p_prbMapElm->p_sec_desc[sym_id][0]; + + dst = xran_add_hdr_offset(dst, p_prbMapElm->compMethod); + + if (p_sec_desc == NULL) { + printf("p_sec_desc == NULL\n"); + exit(-1); + } + uint16_t *dst16 = (uint16_t *)dst; + + int pos_len = 0; + int neg_len = 0; + + if (p_prbMapElm->nRBStart < (nPRBs >> 1)) // there are PRBs left of DC + neg_len = min((nPRBs * 6) - (p_prbMapElm->nRBStart * 12), p_prbMapElm->nRBSize * N_SC_PER_PRB); + pos_len = (p_prbMapElm->nRBSize * N_SC_PER_PRB) - neg_len; + // Calculation of the pointer for the section in the buffer. + // start of positive frequency component + uint16_t *src1 = (uint16_t *)&pos[(neg_len == 0) ? ((p_prbMapElm->nRBStart * N_SC_PER_PRB) - (nPRBs * 6)) : 0]; + // start of negative frequency component + uint16_t *src2 = (uint16_t *)&pos[(p_prbMapElm->nRBStart * N_SC_PER_PRB) + fftsize - (nPRBs * 6)]; + + uint32_t local_src[p_prbMapElm->nRBSize * N_SC_PER_PRB] __attribute__((aligned(64))); + memcpy((void *)local_src, (void *)src2, neg_len * 4); + memcpy((void *)&local_src[neg_len], (void *)src1, pos_len * 4); + if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_NONE) { + payload_len = p_prbMapElm->nRBSize * N_SC_PER_PRB * 4L; + /* convert to Network order */ + // NOTE: ggc 11 knows how to generate AVX2 for this! + for (idx = 0; idx < (pos_len + neg_len) * 2; idx++) + ((uint16_t *)dst16)[idx] = htons(((uint16_t *)local_src)[idx]); + } else if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) { + struct xranlib_compress_request bfp_com_req; + struct xranlib_compress_response bfp_com_rsp; + payload_len = (3 * p_prbMapElm->iqWidth + 1) * p_prbMapElm->nRBSize; + memset(&bfp_com_req, 0, sizeof(struct xranlib_compress_request)); + memset(&bfp_com_rsp, 0, sizeof(struct xranlib_compress_response)); + + bfp_com_req.data_in = (int16_t *)local_src; + bfp_com_req.numRBs = p_prbMapElm->nRBSize; + bfp_com_req.len = payload_len; + bfp_com_req.compMethod = p_prbMapElm->compMethod; + bfp_com_req.iqWidth = p_prbMapElm->iqWidth; + + bfp_com_rsp.data_out = (int8_t *)dst; + bfp_com_rsp.len = 0; + + xranlib_compress_avx512(&bfp_com_req, &bfp_com_rsp); + + } else { + printf("p_prbMapElm->compMethod == %d is not supported\n", p_prbMapElm->compMethod); + exit(-1); + } + + p_sec_desc->iq_buffer_offset = RTE_PTR_DIFF(dst, u8dptr); + p_sec_desc->iq_buffer_len = payload_len; + + dst += payload_len; + dst = xran_add_hdr_offset(dst, p_prbMapElm->compMethod); + } + + // The tti should be updated as it increased. + pRbMap->tti_id = tti; + + } else { + printf("ptr ==NULL\n"); + exit(-1); // fails here?? + } + } + } + } + return (0); +} diff --git a/radio/fhi_72/oaioran.h b/radio/fhi_72/oaioran.h new file mode 100644 index 0000000000..a20f6c80d3 --- /dev/null +++ b/radio/fhi_72/oaioran.h @@ -0,0 +1,37 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef OAIORAN_H +#define OAIORAN_H + +#include +#include "xran_fh_o_du.h" + +typedef struct { + uint32_t tti; + uint32_t sl; + uint32_t f; +} oran_sync_info_t; + +void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status); +int oai_physide_dl_tti_call_back(void *param); + +#endif /* OAIORAN_H */ diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c new file mode 100644 index 0000000000..3c201732c9 --- /dev/null +++ b/radio/fhi_72/oran-config.c @@ -0,0 +1,886 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "oran-config.h" +#include "oran-params.h" +#include "common/utils/assertions.h" +#include "common_lib.h" + +#include "xran_fh_o_du.h" +#include "xran_cp_api.h" +#include "rte_ether.h" + +#include "stdio.h" +#include "string.h" + +static void print_fh_eowd_cmn(unsigned index, const struct xran_ecpri_del_meas_cmn *eowd_cmn) +{ + printf("\ + eowd_cmn[%d]:\n\ + initiator_en %d\n\ + numberOfSamples %d\n\ + filterType %d\n\ + responseTo %ld\n\ + measVf %d\n\ + measState %d\n\ + measId %d\n\ + measMethod %d\n\ + owdm_enable %d\n\ + owdm_PlLength %d\n", + index, + eowd_cmn->initiator_en, + eowd_cmn->numberOfSamples, + eowd_cmn->filterType, + eowd_cmn->responseTo, + eowd_cmn->measVf, + eowd_cmn->measState, + eowd_cmn->measId, + eowd_cmn->measMethod, + eowd_cmn->owdm_enable, + eowd_cmn->owdm_PlLength); +} + +static void print_fh_eowd_port(unsigned index, unsigned vf, const struct xran_ecpri_del_meas_port *eowd_port) +{ + printf("\ + eowd_port[%d][%d]:\n\ + t1 %ld\n\ + t2 %ld\n\ + tr %ld\n\ + delta %ld\n\ + portid %d\n\ + runMeas %d\n\ + currentMeasID %d\n\ + msState %d\n\ + numMeas %d\n\ + txDone %d\n\ + rspTimerIdx %ld\n\ + delaySamples [%ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld]\n\ + delayAvg %ld\n", + index, + vf, + eowd_port->t1, + eowd_port->t2, + eowd_port->tr, + eowd_port->delta, + eowd_port->portid, + eowd_port->runMeas, + eowd_port->currentMeasID, + eowd_port->msState, + eowd_port->numMeas, + eowd_port->txDone, + eowd_port->rspTimerIdx, + eowd_port->delaySamples[0], + eowd_port->delaySamples[1], + eowd_port->delaySamples[2], + eowd_port->delaySamples[3], + eowd_port->delaySamples[4], + eowd_port->delaySamples[5], + eowd_port->delaySamples[6], + eowd_port->delaySamples[7], + eowd_port->delaySamples[8], + eowd_port->delaySamples[9], + eowd_port->delaySamples[10], + eowd_port->delaySamples[11], + eowd_port->delaySamples[12], + eowd_port->delaySamples[13], + eowd_port->delaySamples[14], + eowd_port->delaySamples[15], + eowd_port->delayAvg); +} + +static void print_fh_init_io_cfg(const struct xran_io_cfg *io_cfg) +{ + printf("\ + io_cfg:\n\ + id %d (%s)\n\ + num_vfs %d\n\ + num_rxq %d\n\ + dpdk_dev [%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s]\n\ + bbdev_dev %s\n\ + bbdev_mode %d\n\ + dpdkIoVaMode %d\n\ + dpdkMemorySize %d\n", + io_cfg->id, + io_cfg->id == 0 ? "O-DU" : "O-RU", + io_cfg->num_vfs, + io_cfg->num_rxq, + io_cfg->dpdk_dev[XRAN_UP_VF], + io_cfg->dpdk_dev[XRAN_CP_VF], + io_cfg->dpdk_dev[XRAN_UP_VF1], + io_cfg->dpdk_dev[XRAN_CP_VF1], + io_cfg->dpdk_dev[XRAN_UP_VF2], + io_cfg->dpdk_dev[XRAN_CP_VF2], + io_cfg->dpdk_dev[XRAN_UP_VF3], + io_cfg->dpdk_dev[XRAN_CP_VF3], + io_cfg->dpdk_dev[XRAN_UP_VF4], + io_cfg->dpdk_dev[XRAN_CP_VF4], + io_cfg->dpdk_dev[XRAN_UP_VF5], + io_cfg->dpdk_dev[XRAN_CP_VF5], + io_cfg->dpdk_dev[XRAN_UP_VF6], + io_cfg->dpdk_dev[XRAN_CP_VF6], + io_cfg->dpdk_dev[XRAN_UP_VF7], + io_cfg->dpdk_dev[XRAN_CP_VF7], + io_cfg->bbdev_dev[0], + io_cfg->bbdev_mode, + io_cfg->dpdkIoVaMode, + io_cfg->dpdkMemorySize); + + printf("\ + core %d\n\ + system_core %d\n\ + pkt_proc_core %016lx\n\ + pkt_proc_core_64_127 %016lx\n\ + pkt_aux_core %d\n\ + timing_core %d\n\ + port [%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, ]\n\ + io_sleep %d\n\ + nEthLinePerPort %d\n\ + nEthLineSpeed %d\n\ + one_vf_cu_plane %d\n", + io_cfg->core, + io_cfg->system_core, + io_cfg->pkt_proc_core, + io_cfg->pkt_proc_core_64_127, + io_cfg->pkt_aux_core, + io_cfg->timing_core, + io_cfg->port[XRAN_UP_VF], + io_cfg->port[XRAN_CP_VF], + io_cfg->port[XRAN_UP_VF1], + io_cfg->port[XRAN_CP_VF1], + io_cfg->port[XRAN_UP_VF2], + io_cfg->port[XRAN_CP_VF2], + io_cfg->port[XRAN_UP_VF3], + io_cfg->port[XRAN_CP_VF3], + io_cfg->port[XRAN_UP_VF4], + io_cfg->port[XRAN_CP_VF4], + io_cfg->port[XRAN_UP_VF5], + io_cfg->port[XRAN_CP_VF5], + io_cfg->port[XRAN_UP_VF6], + io_cfg->port[XRAN_CP_VF6], + io_cfg->port[XRAN_UP_VF7], + io_cfg->port[XRAN_CP_VF7], + io_cfg->io_sleep, + io_cfg->nEthLinePerPort, + io_cfg->nEthLineSpeed, + io_cfg->one_vf_cu_plane); + print_fh_eowd_cmn(0, &io_cfg->eowd_cmn[0]); + print_fh_eowd_cmn(1, &io_cfg->eowd_cmn[1]); + for (int i = 0; i < 2; ++i) + for (int v = 0; v < io_cfg->num_vfs; ++v) + print_fh_eowd_port(i, v, &io_cfg->eowd_port[i][v]); +} + +static void print_fh_init_eaxcid_conf(const struct xran_eaxcid_config *eaxcid_conf) +{ + printf("\ + eAxCId_conf:\n\ + mask_cuPortId 0x%04x\n\ + mask_bandSectorId 0x%04x\n\ + mask_ccId 0x%04x\n\ + mask_ruPortId 0x%04x\n\ + bit_cuPortId %d\n\ + bit_bandSectorId %d\n\ + bit_ccId %d\n\ + bit_ruPortId %d\n", + eaxcid_conf->mask_cuPortId, + eaxcid_conf->mask_bandSectorId, + eaxcid_conf->mask_ccId, + eaxcid_conf->mask_ruPortId, + eaxcid_conf->bit_cuPortId, + eaxcid_conf->bit_bandSectorId, + eaxcid_conf->bit_ccId, + eaxcid_conf->bit_ruPortId); +} + +static void print_ether_addr(const char *pre, int num_ether, const struct rte_ether_addr *addrs) +{ + printf("%s [", pre); + for (int i = 0; i < num_ether; ++i) { + char buf[18]; + rte_ether_format_addr(buf, 18, &addrs[i]); + printf("%s", buf); + if (i != num_ether - 1) + printf(", "); + } + printf("]\n"); +} + +void print_fh_init(const struct xran_fh_init *fh_init) +{ + printf("xran_fh_init:\n"); + print_fh_init_io_cfg(&fh_init->io_cfg); + print_fh_init_eaxcid_conf(&fh_init->eAxCId_conf); + printf("\ + xran_ports %d\n\ + dpdkBasebandFecMode %d\n\ + dpdkBasebandDevice %s\n\ + filePrefix %s\n\ + mtu %d\n", + fh_init->xran_ports, + fh_init->dpdkBasebandFecMode, + fh_init->dpdkBasebandDevice, + fh_init->filePrefix, + fh_init->mtu); + print_ether_addr(" p_o_du_addr", fh_init->xran_ports * fh_init->io_cfg.num_vfs, (struct rte_ether_addr *)fh_init->p_o_du_addr); + print_ether_addr(" p_o_ru_addr", fh_init->xran_ports * fh_init->io_cfg.num_vfs, (struct rte_ether_addr *)fh_init->p_o_ru_addr); + printf("\ + totalBfWeights %d\n", + fh_init->totalBfWeights); +} + +static void print_prach_config(const struct xran_prach_config *prach_conf) +{ + printf("\ + prach_config:\n\ + nPrachConfIdx %d\n\ + nPrachSubcSpacing %d\n\ + nPrachZeroCorrConf %d\n\ + nPrachRestrictSet %d\n\ + nPrachRootSeqIdx %d\n\ + nPrachFreqStart %d\n\ + nPrachFreqOffset %d\n\ + nPrachFilterIdx %d\n\ + startSymId %d\n\ + lastSymId %d\n\ + startPrbc %d\n\ + numPrbc %d\n\ + timeOffset %d\n\ + freqOffset %d\n\ + eAxC_offset %d\n", + prach_conf->nPrachConfIdx, + prach_conf->nPrachSubcSpacing, + prach_conf->nPrachZeroCorrConf, + prach_conf->nPrachRestrictSet, + prach_conf->nPrachRootSeqIdx, + prach_conf->nPrachFreqStart, + prach_conf->nPrachFreqOffset, + prach_conf->nPrachFilterIdx, + prach_conf->startSymId, + prach_conf->lastSymId, + prach_conf->startPrbc, + prach_conf->numPrbc, + prach_conf->timeOffset, + prach_conf->freqOffset, + prach_conf->eAxC_offset); +} + +static void print_srs_config(const struct xran_srs_config *srs_conf) +{ + printf("\ + srs_config:\n\ + symbMask %04x\n\ + eAxC_offset %d\n", + srs_conf->symbMask, + srs_conf->eAxC_offset); +} + +static void print_frame_config(const struct xran_frame_config *frame_conf) +{ + printf("\ + frame_conf:\n\ + nFrameDuplexType %s\n\ + nNumerology %d\n\ + nTddPeriod %d\n", + frame_conf->nFrameDuplexType == XRAN_TDD ? "TDD" : "FDD", + frame_conf->nNumerology, + frame_conf->nTddPeriod); + for (int i = 0; i < frame_conf->nTddPeriod; ++i) { + printf(" sSlotConfig[%d]: ", i); + for (int s = 0; s < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++s) { + uint8_t nSymbolType = frame_conf->sSlotConfig[i].nSymbolType[s]; + printf("%c", nSymbolType == 0 ? 'D' : (nSymbolType == 1 ? 'U' : 'G')); + } + printf("\n"); + } +} + +static void print_ru_config(const struct xran_ru_config *ru_conf) +{ + printf("\ + ru_config:\n\ + xranTech %s\n\ + xranCat %s\n\ + xranCompHdrType %s\n\ + iqWidth %d\n\ + compMeth %d\n\ + iqWidth_PRACH %d\n\ + compMeth_PRACH %d\n\ + fftSize %d\n\ + byteOrder %s\n\ + iqOrder %s\n\ + xran_max_frame %d\n", + ru_conf->xranTech == XRAN_RAN_5GNR ? "NR" : "LTE", + ru_conf->xranCat == XRAN_CATEGORY_A ? "A" : "B", + ru_conf->xranCompHdrType == XRAN_COMP_HDR_TYPE_DYNAMIC ? "dynamic" : "static", + ru_conf->iqWidth, + ru_conf->compMeth, + ru_conf->iqWidth_PRACH, + ru_conf->compMeth_PRACH, + ru_conf->fftSize, + ru_conf->byteOrder == XRAN_NE_BE_BYTE_ORDER ? "network/BE" : "CPU/LE", + ru_conf->iqOrder == XRAN_I_Q_ORDER ? "I_Q" : "Q_I", + ru_conf->xran_max_frame); +} + +void print_fh_config(const struct xran_fh_config *fh_config) +{ + printf("xran_fh_config:\n"); + printf("\ + dpdk_port %d\n\ + sector_id %d\n\ + nCC %d\n\ + neAxc %d\n\ + neAxcUl %d\n\ + nAntElmTRx %d\n\ + nDLFftSize %d\n\ + nULFftSize %d\n\ + nDLRBs %d\n\ + nULRBs %d\n\ + nDLAbsFrePointA %d\n\ + nULAbsFrePointA %d\n\ + nDLCenterFreqARFCN %d\n\ + nULCenterFreqARFCN %d\n\ + ttiCb %p\n\ + ttiCbParam %p\n", + fh_config->dpdk_port, + fh_config->sector_id, + fh_config->nCC, + fh_config->neAxc, + fh_config->neAxcUl, + fh_config->nAntElmTRx, + fh_config->nDLFftSize, + fh_config->nULFftSize, + fh_config->nDLRBs, + fh_config->nULRBs, + fh_config->nDLAbsFrePointA, + fh_config->nULAbsFrePointA, + fh_config->nDLCenterFreqARFCN, + fh_config->nULCenterFreqARFCN, + fh_config->ttiCb, + fh_config->ttiCbParam); + + printf("\ + Tadv_cp_dl %d\n\ + T2a_min_cp_dl %d\n\ + T2a_max_cp_dl %d\n\ + T2a_min_cp_ul %d\n\ + T2a_max_cp_ul %d\n\ + T2a_min_up %d\n\ + T2a_max_up %d\n\ + Ta3_min %d\n\ + Ta3_max %d\n\ + T1a_min_cp_dl %d\n\ + T1a_max_cp_dl %d\n\ + T1a_min_cp_ul %d\n\ + T1a_max_cp_ul %d\n\ + T1a_min_up %d\n\ + T1a_max_up %d\n\ + Ta4_min %d\n\ + Ta4_max %d\n", + fh_config->Tadv_cp_dl, + fh_config->T2a_min_cp_dl, + fh_config->T2a_max_cp_dl, + fh_config->T2a_min_cp_ul, + fh_config->T2a_max_cp_ul, + fh_config->T2a_min_up, + fh_config->T2a_max_up, + fh_config->Ta3_min, + fh_config->Ta3_max, + fh_config->T1a_min_cp_dl, + fh_config->T1a_max_cp_dl, + fh_config->T1a_min_cp_ul, + fh_config->T1a_max_cp_ul, + fh_config->T1a_min_up, + fh_config->T1a_max_up, + fh_config->Ta4_min, + fh_config->Ta4_max); + + printf("\ + enableCP %d\n\ + prachEnable %d\n\ + srsEnable %d\n\ + puschMaskEnable %d\n\ + puschMaskSlot %d\n\ + cp_vlan_tag %d\n\ + up_vlan_tag %d\n\ + debugStop %d\n\ + debugStopCount %d\n\ + DynamicSectionEna %d\n\ + GPS_Alpha %d\n\ + GPS_Beta %d\n", + fh_config->enableCP, + fh_config->prachEnable, + fh_config->srsEnable, + fh_config->puschMaskEnable, + fh_config->puschMaskSlot, + fh_config->cp_vlan_tag, + fh_config->up_vlan_tag, + fh_config->debugStop, + fh_config->debugStopCount, + fh_config->DynamicSectionEna, + fh_config->GPS_Alpha, + fh_config->GPS_Beta); + + print_prach_config(&fh_config->prach_conf); + print_srs_config(&fh_config->srs_conf); + print_frame_config(&fh_config->frame_conf); + print_ru_config(&fh_config->ru_conf); + + printf("\ + bbdev_enc %p\n\ + bbdev_dec %p\n\ + tx_cp_eAxC2Vf [not implemented by fhi_lib]\n\ + tx_up_eAxC2Vf [not implemented by fhi_lib]\n\ + rx_cp_eAxC2Vf [not implemented by fhi_lib]\n\ + rx_up_eAxC2Vf [not implemented by fhi_lib]\n\ + log_level %d\n\ + max_sections_per_slot %d\n\ + max_sections_per_symbol %d\n", + fh_config->bbdev_enc, + fh_config->bbdev_dec, + fh_config->log_level, + fh_config->max_sections_per_slot, + fh_config->max_sections_per_symbol); +} + +static const paramdef_t *gpd(const paramdef_t *pd, int num, const char *name) +{ + /* the config module does not know const-correctness... */ + int idx = config_paramidx_fromname((paramdef_t *)pd, num, (char *)name); + DevAssert(idx >= 0); + return &pd[idx]; +} + +static uint64_t get_u64_mask(const paramdef_t *pd) +{ + DevAssert(pd != NULL); + AssertFatal(pd->numelt > 0, "no entries for creation of mask\n"); + uint64_t mask = 0; + for (int i = 0; i < pd->numelt; ++i) { + int num = pd->iptr[i]; + AssertFatal(num >= 0 && num < 64, "cannot put element of %d in 64-bit mask\n", num); + mask |= 1 << num; + } + return mask; +} + +static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, int nump) +{ + DevAssert(fhip != NULL); + int num_dev = gpd(fhip, nump, ORAN_CONFIG_DPDK_DEVICES)->numelt; + AssertFatal(num_dev > 0, "need to provide DPDK devices for O-RAN 7.2 Fronthaul\n"); + AssertFatal(num_dev < 17, "too many DPDK devices for O-RAN 7.2 Fronthaul\n"); + + io_cfg->id = 0; // 0 = O-DU + io_cfg->num_vfs = num_dev; + io_cfg->num_rxq = 2; // Assume two HW RX queues per RU + for (int i = 0; i < num_dev; ++i) + io_cfg->dpdk_dev[i] = strdup(gpd(fhip, nump, ORAN_CONFIG_DPDK_DEVICES)->strlistptr[i]); + //io_cfg->bbdev_dev = NULL; + io_cfg->bbdev_mode = XRAN_BBDEV_NOT_USED; // none + io_cfg->dpdkIoVaMode = 0; /* IOVA mode */ + io_cfg->dpdkMemorySize = 0; /* DPDK memory size */ + io_cfg->core = *gpd(fhip, nump, ORAN_CONFIG_IO_CORE)->iptr; + io_cfg->system_core = 0; /* TODO how called in sample app? */ + io_cfg->pkt_proc_core = get_u64_mask(gpd(fhip, nump, ORAN_CONFIG_WORKER_CORES)); + io_cfg->pkt_proc_core_64_127 = 0x0; // bitmap 0 -> no core + io_cfg->pkt_aux_core = 0; /* sapmle app says 0 = "do not start" */ + io_cfg->timing_core = *gpd(fhip, nump, ORAN_CONFIG_IO_CORE)->iptr; /* sample app: equal to io_core */ + //io_cfg->port = {0}; // all 0 + io_cfg->io_sleep = 0; // no sleep + io_cfg->nEthLinePerPort = *gpd(fhip, nump, ORAN_CONFIG_NETHPERPORT)->uptr; + io_cfg->nEthLineSpeed = *gpd(fhip, nump, ORAN_CONFIG_NETHSPEED)->uptr; + io_cfg->one_vf_cu_plane = 0; // false: C/U-plane don't share VF + // io_cfg->eowd_cmn[0] // all 0 + // io_cfg->eowd_cmn[1] // all 0 + // io_cfg->eowd_port[0]... // all 0 + + return true; +} + +static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat) +{ + // values taken from sample app + switch (cat) { + case XRAN_CATEGORY_A: + eaxcid_conf->mask_cuPortId = 0xf000; + eaxcid_conf->mask_bandSectorId = 0x0f00; + eaxcid_conf->mask_ccId = 0x00f0; + eaxcid_conf->mask_ruPortId = 0x000f; + eaxcid_conf->bit_cuPortId = 12; + eaxcid_conf->bit_bandSectorId = 8; + eaxcid_conf->bit_ccId = 4; + eaxcid_conf->bit_ruPortId = 0; + break; + case XRAN_CATEGORY_B: + eaxcid_conf->mask_cuPortId = 0xf000; + eaxcid_conf->mask_bandSectorId = 0x0c00; + eaxcid_conf->mask_ccId = 0x0300; + eaxcid_conf->mask_ruPortId = 0x000f; + eaxcid_conf->bit_cuPortId = 12; + eaxcid_conf->bit_bandSectorId = 10; + eaxcid_conf->bit_ccId = 8; + eaxcid_conf->bit_ruPortId = 0; + break; + default: + return false; + } + + return true; +} + +uint8_t *get_ether_addr(const char *addr, struct rte_ether_addr *ether_addr) +{ +#pragma GCC diagnostic push + // the following line disables the deprecated warning +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + int ret = rte_ether_unformat_addr(addr, ether_addr); +#pragma GCC diagnostic pop + if (ret == 0) + return (uint8_t *)ether_addr; + return NULL; +} + +bool set_fh_init(struct xran_fh_init *fh_init) +{ + memset(fh_init, 0, sizeof(*fh_init)); + + // verify oran section is present: we don't have a list but the below returns + // numelt > 0 if the block is there + paramlist_def_t pl = {0}; + strncpy(pl.listname, CONFIG_STRING_ORAN, sizeof(pl.listname) - 1); + config_getlist(config_get_if(), &pl, NULL, 0, /* prefix */ NULL); + if (pl.numelt == 0) { + printf("Configuration section \"%s\" not present: cannot initialize fhi_lib!\n", CONFIG_STRING_ORAN); + return false; + } + + paramdef_t fhip[] = ORAN_GLOBALPARAMS_DESC; + int nump = sizeofArray(fhip); + int ret = config_get(config_get_if(), fhip, nump, CONFIG_STRING_ORAN); + if (ret <= 0) { + printf("problem reading section \"%s\"\n", CONFIG_STRING_ORAN); + return false; + } + + paramdef_t FHconfigs[] = ORAN_FH_DESC; + paramlist_def_t FH_ConfigList = {CONFIG_STRING_ORAN_FH}; + char aprefix[MAX_OPTNAME_SIZE] = {0}; + sprintf(aprefix, "%s", CONFIG_STRING_ORAN); + const int nfh = sizeofArray(FHconfigs); + config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix); + int num_rus = FH_ConfigList.numelt; + int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt; + int num_du_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt; + int num_vfs = gpd(fhip, nump, ORAN_CONFIG_DPDK_DEVICES)->numelt; + if (num_ru_addr != num_du_addr) { + printf("need to have same number of DUs and RUs!\n"); + return false; + } + if (num_ru_addr != num_vfs) { + printf("need to have as many RU/DU entries as DPDK devices (one VF for CP and UP each)\n"); + return false; + } + + if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump)) + return false; + if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, XRAN_CATEGORY_A)) + return false; + + fh_init->xran_ports = num_rus; + fh_init->dpdkBasebandFecMode = 0; + fh_init->dpdkBasebandDevice = NULL; + fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr); // see DPDK --file-prefix + fh_init->mtu = *gpd(fhip, nump, ORAN_CONFIG_MTU)->uptr; + + // if multiple RUs: xran_ethdi_init_dpdk_io() iterates over + // &p_o_ru_addr[i] + char **du_addrs = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr; + fh_init->p_o_du_addr = calloc(num_du_addr, sizeof(struct rte_ether_addr)); + AssertFatal(fh_init->p_o_du_addr != NULL, "out of memory\n"); + for (int i = 0; i < num_du_addr; ++i) { + struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_du_addr; + if (get_ether_addr(du_addrs[i], &ea[i]) == NULL) { + printf("could not read ethernet address '%s' for DU!\n", du_addrs[i]); + return false; + } + } + fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr)); + char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr; + AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n"); + for (int i = 0; i < num_ru_addr; ++i) { + struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr; + if (get_ether_addr(ru_addrs[i], &ea[i]) == NULL) { + printf("could not read ethernet address '%s' for RU!\n", ru_addrs[i]); + return false; + } + } + fh_init->totalBfWeights = 32; + + return true; +} + +static enum xran_cp_filterindex get_prach_filterindex_fr1(duplex_mode_t mode, int prach_index) +{ + if (mode == duplex_mode_TDD) { + // 38.211 table 6.3.3.2-3 "unpaired spectrum" -> TDD + switch (prach_index) { + case 0 ... 39: + case 256 ... 262: + return XRAN_FILTERINDEX_PRACH_012; + case 40 ... 66: + return XRAN_FILTERINDEX_PRACH_3; + case 67 ... 255: + return XRAN_FILTERINDEX_PRACH_ABC; + } + } else if (mode == duplex_mode_FDD) { + // 38.211 table 6.3.3.2-2 "paired spectrum" -> FDD + switch (prach_index) { + case 0 ... 59: + return XRAN_FILTERINDEX_PRACH_012; + case 60 ... 86: + return XRAN_FILTERINDEX_PRACH_3; + case 87 ... 255: + return XRAN_FILTERINDEX_PRACH_ABC; + default: + AssertFatal(false, "unknown PRACH index %d\n", prach_index); + } + } else { + AssertFatal(false, "unsupported duplex mode %d\n", mode); + } + return XRAN_FILTERINDEX_STANDARD; +} + +// PRACH guard interval. Raymond: "[it] is not in the configuration, (i.e. it +// is deterministic depending on others). LiteON must hard-code this in the +// O-RU itself, benetel doesn't (as O-RAN specifies). So we will need to tell +// the driver what the case is and provide" +// this is a hack +int g_kbar; + +static bool set_fh_prach_config(const openair0_config_t *oai0, + const paramdef_t *prachp, + int nprach, + struct xran_prach_config *prach_config) +{ + const split7_config_t *s7cfg = &oai0->split7; + + // for FR2, need at least to update nPrachFilterIdx + AssertFatal(oai0->nr_band < 100, "can only handle FR1!\n"); + + prach_config->nPrachConfIdx = s7cfg->prach_index; + prach_config->nPrachSubcSpacing = oai0->nr_scs_for_raster; + prach_config->nPrachZeroCorrConf = 0; + prach_config->nPrachRestrictSet = 0; + prach_config->nPrachRootSeqIdx = 0; + prach_config->nPrachFreqStart = s7cfg->prach_freq_start; + prach_config->nPrachFreqOffset = (s7cfg->prach_freq_start * 12 - oai0->num_rb_dl * 6) * 2; + prach_config->nPrachFilterIdx = get_prach_filterindex_fr1(oai0->duplex_mode, s7cfg->prach_index); + prach_config->startSymId = 0; + prach_config->lastSymId = 0; + prach_config->startPrbc = 0; + prach_config->numPrbc = 0; + prach_config->timeOffset = 0; + prach_config->freqOffset = 0; + prach_config->eAxC_offset = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_EAXC_OFFSET)->u8ptr; + + g_kbar = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_KBAR)->uptr; + + return true; +} + +static bool set_fh_srs_config(struct xran_srs_config *srs_config) +{ + srs_config->symbMask = 0; + srs_config->eAxC_offset = 8; + return true; +} + +static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame_config *frame_config) +{ + const split7_config_t *s7cfg = &oai0->split7; + frame_config->nFrameDuplexType = oai0->duplex_mode == duplex_mode_TDD ? XRAN_TDD : XRAN_FDD; + frame_config->nNumerology = oai0->nr_scs_for_raster; + frame_config->nTddPeriod = s7cfg->n_tdd_period; + + struct xran_slot_config *sc = &frame_config->sSlotConfig[0]; + for (int slot = 0; slot < frame_config->nTddPeriod; ++slot) + for (int sym = 0; sym < 14; ++sym) + sc[slot].nSymbolType[sym] = s7cfg->slot_dirs[slot].sym_dir[sym]; + return true; +} + +static bool set_fh_ru_config(const paramdef_t *rup, int nru, struct xran_ru_config *ru_config) +{ + ru_config->xranTech = XRAN_RAN_5GNR; + ru_config->xranCat = XRAN_CATEGORY_A; + ru_config->xranCompHdrType = XRAN_COMP_HDR_TYPE_STATIC; + ru_config->iqWidth = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH)->uptr; + AssertFatal(ru_config->iqWidth <= 16, "IQ Width cannot be > 16!\n"); + ru_config->compMeth = ru_config->iqWidth < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; + ru_config->iqWidth_PRACH = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH_PRACH)->uptr; + AssertFatal(ru_config->iqWidth_PRACH <= 16, "IQ Width for PRACH cannot be > 16!\n"); + ru_config->compMeth_PRACH = ru_config->iqWidth_PRACH < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; + ru_config->fftSize = *gpd(rup, nru, ORAN_RU_CONFIG_FFT_SIZE)->uptr; + ru_config->byteOrder = XRAN_NE_BE_BYTE_ORDER; + ru_config->iqOrder = XRAN_I_Q_ORDER; + ru_config->xran_max_frame = 0; + return true; +} + +static bool set_maxmin_pd(const paramdef_t *pd, int num, const char *name, uint16_t *min, uint16_t *max) +{ + const paramdef_t *p = gpd(pd, num, name); + if (p->numelt != 2) { + printf("parameter list \"%s\" should have exactly two parameters (max&min), but has %d\n", name, num); + return false; + } + *min = p->uptr[0]; + *max = p->uptr[1]; + if (*min > *max) { + printf("min parameter of \"%s\" is larger than max!\n", name); + return false; + } + return true; +} + +extern uint32_t to_nrarfcn(int nr_bandP, uint64_t dl_CarrierFreq, uint8_t scs_index, uint32_t bw); +bool set_fh_config(int ru_idx, int num_rus, const openair0_config_t *oai0, struct xran_fh_config *fh_config) +{ + AssertFatal(num_rus == 1 || num_rus == 2, "only support 1 or 2 RUs as of now\n"); + AssertFatal(ru_idx < num_rus, "illegal ru_idx %d: must be < %d\n", ru_idx, num_rus); + DevAssert(oai0->tx_num_channels > 0 && oai0->rx_num_channels > 0); + DevAssert(oai0->tx_bw > 0 && oai0->rx_bw > 0); + //AssertFatal(oai0->tx_num_channels == oai0->rx_num_channels, "cannot handle unequal number of TX/RX channels\n"); + DevAssert(oai0->tx_freq[0] > 0); + for (int i = 1; i < oai0->tx_num_channels; ++i) + DevAssert(oai0->tx_freq[0] == oai0->tx_freq[i]); + DevAssert(oai0->rx_freq[0] > 0); + for (int i = 1; i < oai0->rx_num_channels; ++i) + DevAssert(oai0->rx_freq[0] == oai0->rx_freq[i]); + DevAssert(oai0->nr_band > 0); + DevAssert(oai0->nr_scs_for_raster > 0); + + // we simply assume that the loading process provides function to_nrarfcn() + // to calculate the ARFCN numbers from frequency. That is not clean, but the + // best we can do without copy-pasting the function. + uint32_t nDLCenterFreqARFCN = to_nrarfcn(oai0->nr_band, oai0->tx_freq[0], oai0->nr_scs_for_raster, oai0->tx_bw); + uint32_t nULCenterFreqARFCN = to_nrarfcn(oai0->nr_band, oai0->rx_freq[0], oai0->nr_scs_for_raster, oai0->rx_bw); + + paramdef_t FHconfigs[] = ORAN_FH_DESC; + paramlist_def_t FH_ConfigList = {CONFIG_STRING_ORAN_FH}; + char aprefix[MAX_OPTNAME_SIZE] = {0}; + sprintf(aprefix, "%s", CONFIG_STRING_ORAN); + const int nfh = sizeofArray(FHconfigs); + config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix); + if (FH_ConfigList.numelt == 0) { + printf("No configuration section \"%s\" found inside \"%s\": cannot initialize fhi_lib!\n", CONFIG_STRING_ORAN_FH, aprefix); + return false; + } + paramdef_t *fhp = FH_ConfigList.paramarray[ru_idx]; + + paramdef_t rup[] = ORAN_RU_DESC; + int nru = sizeofArray(rup); + sprintf(aprefix, "%s.%s.[%d].%s", CONFIG_STRING_ORAN, CONFIG_STRING_ORAN_FH, ru_idx, CONFIG_STRING_ORAN_RU); + int ret = config_get(config_get_if(), rup, nru, aprefix); + if (ret < 0) { + printf("No configuration section \"%s\": cannot initialize fhi_lib!\n", aprefix); + return false; + } + paramdef_t prachp[] = ORAN_PRACH_DESC; + int nprach = sizeofArray(prachp); + sprintf(aprefix, "%s.%s.[%d].%s", CONFIG_STRING_ORAN, CONFIG_STRING_ORAN_FH, ru_idx, CONFIG_STRING_ORAN_PRACH); + ret = config_get(config_get_if(), prachp, nprach, aprefix); + if (ret < 0) { + printf("No configuration section \"%s\": cannot initialize fhi_lib!\n", aprefix); + return false; + } + + memset(fh_config, 0, sizeof(*fh_config)); + + fh_config->dpdk_port = ru_idx; + fh_config->sector_id = 0; + fh_config->nCC = 1; + fh_config->neAxc = oai0->tx_num_channels / num_rus; + fh_config->neAxcUl = oai0->rx_num_channels / num_rus; + fh_config->nAntElmTRx = oai0->tx_num_channels / num_rus; + fh_config->nDLFftSize = 0; + fh_config->nULFftSize = 0; + fh_config->nDLRBs = oai0->num_rb_dl; + fh_config->nULRBs = oai0->num_rb_dl; + fh_config->nDLAbsFrePointA = 0; + fh_config->nULAbsFrePointA = 0; + fh_config->nDLCenterFreqARFCN = nDLCenterFreqARFCN; + fh_config->nULCenterFreqARFCN = nULCenterFreqARFCN; + fh_config->ttiCb = NULL; + fh_config->ttiCbParam = NULL; + fh_config->Tadv_cp_dl = *gpd(fhp, nfh, ORAN_FH_CONFIG_TADV_CP_DL)->uptr; + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T2A_CP_DL, &fh_config->T2a_min_cp_dl, &fh_config->T2a_max_cp_dl)) + return false; + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T2A_CP_UL, &fh_config->T2a_min_cp_ul, &fh_config->T2a_max_cp_ul)) + return false; + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T2A_UP, &fh_config->T2a_min_up, &fh_config->T2a_max_up)) + return false; + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA3, &fh_config->Ta3_min, &fh_config->Ta3_max)) + return false; + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_DL, &fh_config->T1a_min_cp_dl, &fh_config->T1a_max_cp_dl)) + return false; + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_UL, &fh_config->T1a_min_cp_ul, &fh_config->T1a_max_cp_ul)) + return false; + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_UP, &fh_config->T1a_min_up, &fh_config->T1a_max_up)) + return false; + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA4, &fh_config->Ta4_min, &fh_config->Ta4_max)) + return false; + fh_config->enableCP = 1; + fh_config->prachEnable = 1; + fh_config->srsEnable = 0; + fh_config->puschMaskEnable = 0; + fh_config->puschMaskSlot = 0; + fh_config->cp_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_CP_VLAN_TAG)->uptr; + fh_config->up_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_UP_VLAN_TAG)->uptr; + fh_config->debugStop = 0; + fh_config->debugStopCount = 0; + fh_config->DynamicSectionEna = 0; + fh_config->GPS_Alpha = 0; + fh_config->GPS_Beta = 0; + + if (!set_fh_prach_config(oai0, prachp, nprach, &fh_config->prach_conf)) + return false; + if (!set_fh_srs_config(&fh_config->srs_conf)) + return false; + if (!set_fh_frame_config(oai0, &fh_config->frame_conf)) + return false; + if (!set_fh_ru_config(rup, nru, &fh_config->ru_conf)) + return false; + + fh_config->bbdev_enc = NULL; + fh_config->bbdev_dec = NULL; + // fh_config->tx_cp_eAxC2Vf [not implemented by fhi_lib] + // fh_config->tx_up_eAxC2Vf [not implemented by fhi_lib] + // fh_config->rx_cp_eAxC2Vf [not implemented by fhi_lib] + // fh_config->rx_up_eAxC2Vf [not implemented by fhi_lib] + fh_config->log_level = 1; + fh_config->max_sections_per_slot = 8; + fh_config->max_sections_per_symbol = 8; + + return true; +} diff --git a/radio/fhi_72/oran-config.h b/radio/fhi_72/oran-config.h new file mode 100644 index 0000000000..77f04d8e0c --- /dev/null +++ b/radio/fhi_72/oran-config.h @@ -0,0 +1,40 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef ORAN_CONFIG_H +#define ORAN_CONFIG_H + +#include "stdbool.h" +#include "stdint.h" + +struct xran_fh_init; +void print_fh_init(const struct xran_fh_init *fh_init); +struct xran_fh_config; +void print_fh_config(const struct xran_fh_config *fh_config); + +bool set_fh_init(struct xran_fh_init *fh_init); +struct openair0_config; +bool set_fh_config(int ru_idx, int num_rus, const struct openair0_config *oai0_cfg, struct xran_fh_config *fh_config); + +// hack to workaround LiteOn limitation +extern int g_kbar; + +#endif /* ORAN_CONFIG_H */ diff --git a/radio/fhi_72/oran-init.c b/radio/fhi_72/oran-init.c new file mode 100644 index 0000000000..6586b2cda7 --- /dev/null +++ b/radio/fhi_72/oran-init.c @@ -0,0 +1,465 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "xran_fh_o_du.h" +#include "xran_pkt.h" +#include "xran_pkt_up.h" +#include "rte_ether.h" + +#include "oran-config.h" +#include "oran-init.h" +#include "oaioran.h" + +#include "common/utils/assertions.h" +#include "common_lib.h" + +/* PRACH data samples are 32 bits wide (16bits for I/Q). Each packet contains + * 840 samples for long sequence or 144 for short sequence. The payload length + * is 840*16*2/8 octets.*/ +#ifdef FCN_1_2_6_EARLIER +#define PRACH_PLAYBACK_BUFFER_BYTES (144 * 4L) +#else +#define PRACH_PLAYBACK_BUFFER_BYTES (840 * 4L) +#endif + +// structure holding allocated memory for ports (multiple DUs) and sectors +// (multiple CCs) +static oran_port_instance_t gPortInst[XRAN_PORTS_NUM][XRAN_MAX_SECTOR_NR]; +void *gxran_handle; + +static uint32_t get_nSW_ToFpga_FTH_TxBufferLen(int mu, int sections) +{ + uint32_t xran_max_sections_per_slot = RTE_MAX(sections, XRAN_MIN_SECTIONS_PER_SLOT); + uint32_t overhead = xran_max_sections_per_slot + * (RTE_PKTMBUF_HEADROOM + sizeof(struct rte_ether_hdr) + sizeof(struct xran_ecpri_hdr) + + sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr)); + if (mu <= 1) { + return 13168 + overhead; /* 273*12*4 + 64* + ETH AND ORAN HDRs */ + } else if (mu == 3) { + return 3328 + overhead; + } else { + assert(false && "numerology not supported\n"); + } +} + +static uint32_t get_nFpgaToSW_FTH_RxBufferLen(int mu) +{ + /* note: previous code checked MTU: + * mu <= 1: return mtu > XRAN_MTU_DEFAULT ? 13168 : XRAN_MTU_DEFAULT; + * mu == 3: return mtu > XRAN_MTU_DEFAULT ? 3328 : XRAN_MTU_DEFAULT; + * but I don't understand the interest: if the buffer is a big bigger, there + * is no problem, or we could just set the MTU size as buffer size?! + * Go with Max for the moment + */ + if (mu <= 1) { + return 13168; /* 273*12*4 + 64*/ + } else if (mu == 3) { + return 3328; + } else { + assert(false && "numerology not supported\n"); + } +} + +/* is this necessary? +int32_t set_main_core(uint32_t main_core) +{ + struct sched_param sched_param; + cpu_set_t cpuset; + int32_t result = 0; + memset(&sched_param, 0, sizeof(struct sched_param)); + // set main thread affinity mask to CPU2 + sched_param.sched_priority = 99; + CPU_ZERO(&cpuset); + + printf("This system has %d processors configured and %d processors available.\n", get_nprocs_conf(), get_nprocs()); + + if (main_core < get_nprocs_conf()) + CPU_SET(main_core, &cpuset); + else + return -1; + + if ((result = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset))) { + printf("pthread_setaffinity_np failed: coreId = 2, result = %d\n", result); + } + printf("%s [CPU %2d] [PID: %6d]\n", __FUNCTION__, sched_getcpu(), getpid()); + return result; +} +*/ + +static struct xran_prb_map get_xran_prb_map_dl(const struct xran_fh_config *f) +{ + struct xran_prb_map prbmap = { + .dir = XRAN_DIR_DL, + .xran_port = 0, + .band_id = 0, + .cc_id = 0, + .ru_port_id = 0, + .tti_id = 0, + .nPrbElm = 1, + }; + struct xran_prb_elm *e = &prbmap.prbMap[0]; + e->nStartSymb = 0; + e->numSymb = 14; + e->nRBStart = 0; + e->nRBSize = f->nDLRBs; + e->nBeamIndex = 0; + e->compMethod = f->ru_conf.compMeth; + e->iqWidth = f->ru_conf.iqWidth; + return prbmap; +} + +static struct xran_prb_map get_xran_prb_map_ul(const struct xran_fh_config *f) +{ + struct xran_prb_map prbmap = { + .dir = XRAN_DIR_UL, + .xran_port = 0, + .band_id = 0, + .cc_id = 0, + .ru_port_id = 0, + .tti_id = 0, + .start_sym_id = 0, + .nPrbElm = 1, + }; + struct xran_prb_elm *e = &prbmap.prbMap[0]; + e->nStartSymb = 0; + e->numSymb = 14; + e->nRBStart = 0; + e->nRBSize = f->nULRBs; + e->nBeamIndex = 0; + e->compMethod = f->ru_conf.compMeth; + e->iqWidth = f->ru_conf.iqWidth; + return prbmap; +} + +static uint32_t oran_allocate_uplane_buffers( + void *instHandle, + struct xran_buffer_list list[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN], + struct xran_flat_buffer buf[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT], + uint32_t ant, + uint32_t bufSize) +{ + xran_status_t status; + uint32_t pool; + uint32_t numBufs = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT; + status = xran_bm_init(instHandle, &pool, numBufs, bufSize); + AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status); + printf("xran_bm_init() hInstance %p poolIdx %d elements %d size %d\n", instHandle, pool, numBufs, bufSize); + int count = 0; + for (uint32_t a = 0; a < ant; ++a) { + for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) { + list[a][j].pBuffers = &buf[a][j][0]; + for (uint32_t k = 0; k < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++k) { + struct xran_flat_buffer *fb = &list[a][j].pBuffers[k]; + fb->nElementLenInBytes = bufSize; + fb->nNumberOfElements = 1; + fb->nOffsetInBytes = 0; + void *ptr; + void *mb; + status = xran_bm_allocate_buffer(instHandle, pool, &ptr, &mb); + AssertFatal(XRAN_STATUS_SUCCESS == status && ptr != NULL && mb != NULL, + "Failed at xran_bm_allocate_buffer(), status %d\n", + status); + count++; + fb->pData = ptr; + fb->pCtrl = mb; + memset(ptr, 0, bufSize); + } + } + } + printf("xran_bm_allocate_buffer() hInstance %p poolIdx %d count %d\n", instHandle, pool, count); + return pool; +} + +typedef struct oran_mixed_slot { + uint32_t idx; + uint32_t num_dlsym; + uint32_t num_ulsym; + uint32_t start_ulsym; +} oran_mixed_slot_t; +static oran_mixed_slot_t get_mixed_slot_info(const struct xran_frame_config *fconfig) +{ + oran_mixed_slot_t info = {0}; + for (size_t sl = 0; sl < fconfig->nTddPeriod; ++sl) { + info.num_dlsym = info.num_ulsym = 0; + for (size_t sym = 0; sym < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++sym) { + uint8_t t = fconfig->sSlotConfig[sl].nSymbolType[sym]; + if (t == 0 /* DL */) { + info.num_dlsym++; + } else if (t == 1 /* UL */) { + if (info.num_ulsym == 0) + info.start_ulsym = sym; + info.num_ulsym++; + } else if (t == 2 /* Mixed */) { + info.idx = sl; + } else { + AssertFatal(false, "unknown symbol type %d\n", t); + } + } + if (info.idx > 0) + return info; + } + AssertFatal(false, "could not find mixed slot!\n"); + return info; +} + +typedef struct oran_cplane_prb_config { + uint8_t nTddPeriod; + uint32_t mixed_slot_index; + struct xran_prb_map slotMap; + struct xran_prb_map mixedSlotMap; +} oran_cplane_prb_config; + +static void oran_allocate_cplane_buffers(void *instHandle, + struct xran_buffer_list list[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN], + struct xran_flat_buffer buf[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN], + uint32_t ant, + uint32_t sect, + uint32_t size_of_prb_map, + const oran_cplane_prb_config *prb_conf) +{ + xran_status_t status; + uint32_t poolSec; + uint32_t numBufsSec = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT * sect * XRAN_MAX_FRAGMENT; + uint32_t bufSizeSec = sizeof(struct xran_section_desc); + status = xran_bm_init(instHandle, &poolSec, numBufsSec, bufSizeSec); + AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status); + printf("xran_bm_init() hInstance %p poolIdx %d elements %d size %d\n", instHandle, poolSec, numBufsSec, bufSizeSec); + + uint32_t poolPrb; + uint32_t numBufsPrb = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT; + uint32_t bufSizePrb = size_of_prb_map; + status = xran_bm_init(instHandle, &poolPrb, numBufsPrb, bufSizePrb); + AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status); + printf("xran_bm_init() hInstance %p poolIdx %d elements %d size %d\n", instHandle, poolPrb, numBufsPrb, bufSizePrb); + + uint32_t count1 = 0; + uint32_t count2 = 0; + for (uint32_t a = 0; a < ant; a++) { + for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) { + list[a][j].pBuffers = &buf[a][j]; + struct xran_flat_buffer *fb = list[a][j].pBuffers; + fb->nElementLenInBytes = bufSizePrb; + fb->nNumberOfElements = 1; + fb->nOffsetInBytes = 0; + void *ptr; + void *mb; + status = xran_bm_allocate_buffer(instHandle, poolPrb, &ptr, &mb); + AssertFatal(XRAN_STATUS_SUCCESS == status && ptr != NULL && mb != NULL, + "Failed at xran_bm_allocate_buffer(), status %d\n", + status); + count1++; + fb->pData = ptr; + fb->pCtrl = mb; + + // the original sample app code copies up to size_of_prb_map, but I think + // this is wrong because the way it is computed leads to a number larger + // than sizeof(map) + struct xran_prb_map *p_rb_map = (struct xran_prb_map *)ptr; + const struct xran_prb_map *src = &prb_conf->slotMap; + if ((j % prb_conf->nTddPeriod) == prb_conf->mixed_slot_index) + src = &prb_conf->mixedSlotMap; + memcpy(p_rb_map, src, sizeof(*src)); + + for (uint32_t elm_id = 0; elm_id < p_rb_map->nPrbElm; ++elm_id) { + struct xran_prb_elm *pPrbElem = &p_rb_map->prbMap[elm_id]; + for (uint32_t k = 0; k < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++k) { + for (uint32_t m = 0; m < XRAN_MAX_FRAGMENT; ++m) { + void *sd_ptr; + void *sd_mb; + status = xran_bm_allocate_buffer(instHandle, poolSec, &sd_ptr, &sd_mb); + AssertFatal(XRAN_STATUS_SUCCESS == status, + "Failed at xran_bm_allocate_buffer(), status %d m %d k %d elm_id %d\n", + status, + m, + k, + elm_id); + count2++; + pPrbElem->p_sec_desc[k][m] = sd_ptr; + memset(sd_ptr, 0, sizeof(struct xran_section_desc)); + } + } + } + } + } + printf("xran_bm_allocate_buffer() hInstance %p poolIdx %d count %d\n", instHandle, poolPrb, count1); + printf("xran_bm_allocate_buffer() hInstance %p poolIdx %d count %d\n", instHandle, poolSec, count2); +} + +/* callback not actively used */ +static void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status) +{ + rte_pause(); +} + +static void oran_allocate_buffers(void *handle, + int xran_inst, + int num_sectors, + oran_port_instance_t *portInstances, + const struct xran_fh_config *fh_config) +{ + AssertFatal(num_sectors == 1, "only support one sector at the moment\n"); + oran_port_instance_t *pi = &portInstances[0]; + AssertFatal(handle != NULL, "no handle provided\n"); + uint32_t xran_max_antenna_nr = RTE_MAX(fh_config->neAxc, fh_config->neAxcUl); + uint32_t xran_max_sections_per_slot = RTE_MAX(fh_config->max_sections_per_slot, XRAN_MIN_SECTIONS_PER_SLOT); + uint32_t size_of_prb_map = sizeof(struct xran_prb_map) + sizeof(struct xran_prb_elm) * (xran_max_sections_per_slot - 1); + + pi->buf_list = _mm_malloc(sizeof(*pi->buf_list), 256); + AssertFatal(pi->buf_list != NULL, "out of memory\n"); + oran_buf_list_t *bl = pi->buf_list; + + xran_status_t status; + printf("xran_sector_get_instances() o_xu_id %d xran_handle %p\n", xran_inst, handle); + status = xran_sector_get_instances(xran_inst, handle, num_sectors, &pi->instanceHandle); + printf("-> hInstance %p\n", pi->instanceHandle); + AssertFatal(status == XRAN_STATUS_SUCCESS, "get sector instance failed for XRAN nInstanceNum %d\n", xran_inst); + + const uint32_t txBufSize = get_nSW_ToFpga_FTH_TxBufferLen(fh_config->frame_conf.nNumerology, fh_config->max_sections_per_slot); + oran_allocate_uplane_buffers(pi->instanceHandle, bl->src, bl->bufs.tx, xran_max_antenna_nr, txBufSize); + + oran_mixed_slot_t info = get_mixed_slot_info(&fh_config->frame_conf); + struct xran_prb_map dlPm = get_xran_prb_map_dl(fh_config); + struct xran_prb_map dlPmMixed = dlPm; + dlPmMixed.prbMap[0].nStartSymb = 0; + dlPmMixed.prbMap[0].numSymb = info.num_dlsym; + oran_cplane_prb_config dlConf = { + .nTddPeriod = fh_config->frame_conf.nTddPeriod, + .mixed_slot_index = info.idx, + .slotMap = dlPm, + .mixedSlotMap = dlPmMixed, + }; + oran_allocate_cplane_buffers(pi->instanceHandle, + bl->srccp, + bl->bufs.tx_prbmap, + xran_max_antenna_nr, + xran_max_sections_per_slot, + size_of_prb_map, + &dlConf); + + const uint32_t rxBufSize = get_nFpgaToSW_FTH_RxBufferLen(fh_config->frame_conf.nNumerology); + oran_allocate_uplane_buffers(pi->instanceHandle, bl->dst, bl->bufs.rx, xran_max_antenna_nr, rxBufSize); + + struct xran_prb_map ulPm = get_xran_prb_map_ul(fh_config); + struct xran_prb_map ulPmMixed = ulPm; + ulPmMixed.prbMap[0].nStartSymb = info.start_ulsym; + ulPmMixed.prbMap[0].numSymb = info.num_ulsym; + oran_cplane_prb_config ulConf = { + .nTddPeriod = fh_config->frame_conf.nTddPeriod, + .mixed_slot_index = info.idx, + .slotMap = ulPm, + .mixedSlotMap = ulPmMixed, + }; + oran_allocate_cplane_buffers(pi->instanceHandle, + bl->dstcp, + bl->bufs.rx_prbmap, + xran_max_antenna_nr, + xran_max_sections_per_slot, + size_of_prb_map, + &ulConf); + + // PRACH + const uint32_t prachBufSize = PRACH_PLAYBACK_BUFFER_BYTES; + oran_allocate_uplane_buffers(pi->instanceHandle, bl->prachdst, bl->bufs.prach, xran_max_antenna_nr, prachBufSize); + // PRACH decomp buffer does not have separate DPDK-allocated memory pool + // bufs, it points to the same pool as the prach buffer. Unclear to me why + for (uint32_t a = 0; a < xran_max_antenna_nr; ++a) { + for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) { + bl->prachdstdecomp[a][j].pBuffers = &bl->bufs.prachdecomp[a][j][0]; + for (uint32_t k = 0; k < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++k) { + struct xran_flat_buffer *fb = &bl->prachdstdecomp[a][j].pBuffers[k]; + fb->pData = bl->prachdst[a][j].pBuffers[k].pData; + } + } + } + + struct xran_buffer_list *src[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + struct xran_buffer_list *srccp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + struct xran_buffer_list *dst[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + struct xran_buffer_list *dstcp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + struct xran_buffer_list *prach[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + struct xran_buffer_list *prachdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + for (uint32_t a = 0; a < XRAN_MAX_ANTENNA_NR; ++a) { + for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) { + src[a][j] = &bl->src[a][j]; + srccp[a][j] = &bl->srccp[a][j]; + dst[a][j] = &bl->dst[a][j]; + dstcp[a][j] = &bl->dstcp[a][j]; + prach[a][j] = &bl->prachdst[a][j]; + prachdecomp[a][j] = &bl->prachdstdecomp[a][j]; + } + } + + xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->RxCbTag[0][0]); + xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->PrachCbTag[0][0]); +} + +int *oai_oran_initialize(const openair0_config_t *openair0_cfg) +{ + int32_t xret = 0; + + struct xran_fh_init init = {0}; + if (!set_fh_init(&init)) { + printf("could not read FHI 7.2/ORAN config\n"); + return NULL; + } + print_fh_init(&init); + + /* read all configuration before starting anything */ + struct xran_fh_config xran_fh_config[XRAN_PORTS_NUM] = {0}; + for (int32_t o_xu_id = 0; o_xu_id < init.xran_ports; o_xu_id++) { + if (!set_fh_config(o_xu_id, init.xran_ports, openair0_cfg, &xran_fh_config[o_xu_id])) { + printf("could not read FHI 7.2/RU-specific config\n"); + return NULL; + } + print_fh_config(&xran_fh_config[o_xu_id]); + } + + // if ((xret = set_main_core(init.something)) < 0) { + // printf("set_main_core() failed %d\n", xret); + // exit(-1); + // } + + xret = xran_init(0, NULL, &init, NULL, &gxran_handle); + if (xret != XRAN_STATUS_SUCCESS) { + printf("xran_init failed %d\n", xret); + exit(-1); + } + + /** process all the O-RU|O-DU for use case */ + for (int32_t o_xu_id = 0; o_xu_id < init.xran_ports; o_xu_id++) { + xret = xran_open(gxran_handle, &xran_fh_config[o_xu_id]); + if (xret != XRAN_STATUS_SUCCESS) { + printf("xran_open failed %d\n", xret); + exit(-1); + } + + int sector = 0; + oran_port_instance_t *pi = &gPortInst[o_xu_id][sector]; + oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]); + + if ((xret = xran_reg_physide_cb(gxran_handle, oai_physide_dl_tti_call_back, NULL, 10, XRAN_CB_TTI)) != XRAN_STATUS_SUCCESS) { + printf("xran_reg_physide_cb failed %d\n", xret); + exit(-1); + } + } + + return (void *)gxran_handle; +} diff --git a/radio/fhi_72/oran-init.h b/radio/fhi_72/oran-init.h new file mode 100644 index 0000000000..2c3e5a8ca0 --- /dev/null +++ b/radio/fhi_72/oran-init.h @@ -0,0 +1,63 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef ORAN_INIT_H +#define ORAN_INIT_H + +typedef struct oran_bufs { + struct xran_flat_buffer tx[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT]; + struct xran_flat_buffer tx_prbmap[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + struct xran_flat_buffer rx[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT]; + struct xran_flat_buffer rx_prbmap[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + + struct xran_flat_buffer prach[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT]; + struct xran_flat_buffer prachdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT]; +} oran_bufs_t; + +typedef struct oran_buf_list { + // xran API requires buffer lists as structs of arrays + struct xran_buffer_list src[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + struct xran_buffer_list srccp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + struct xran_buffer_list dst[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + struct xran_buffer_list dstcp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + + struct xran_buffer_list prachdst[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + struct xran_buffer_list prachdstdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; + + oran_bufs_t bufs; +} oran_buf_list_t; + +typedef struct oran_port_instance_t { + oran_buf_list_t *buf_list; + void *instanceHandle; + //uint32_t dpdkPoolIndex[MAX_SW_XRAN_INTERFACE_NUM]; + + struct xran_cb_tag RxCbTag[XRAN_PORTS_NUM][XRAN_MAX_SECTOR_NR]; + struct xran_cb_tag PrachCbTag[XRAN_PORTS_NUM][XRAN_MAX_SECTOR_NR]; +} oran_port_instance_t; + +extern struct xran_fh_config gxran_fh_config[XRAN_PORTS_NUM]; +extern void *gxran_handle; + +struct openair0_config; +int *oai_oran_initialize(const struct openair0_config *openair0_cfg); + +#endif /* ORAN_INIT_H */ diff --git a/radio/fhi_72/oran-params.h b/radio/fhi_72/oran-params.h new file mode 100644 index 0000000000..55157ec94e --- /dev/null +++ b/radio/fhi_72/oran-params.h @@ -0,0 +1,114 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef ORAN_PARAMS_H +#define ORAN_PARAMS_H + +#include "stdbool.h" +#include "stdint.h" + +#define CONFIG_STRING_ORAN "fhi_72" + +#define ORAN_CONFIG_DPDK_DEVICES "dpdk_devices" +#define ORAN_CONFIG_IO_CORE "io_core" +#define ORAN_CONFIG_WORKER_CORES "worker_cores" +#define ORAN_CONFIG_DU_ADDR "du_addr" +#define ORAN_CONFIG_RU_ADDR "ru_addr" +#define ORAN_CONFIG_MTU "mtu" +#define ORAN_CONFIG_FILE_PREFIX "file_prefix" +#define ORAN_CONFIG_NETHPERPORT "eth_lines" +#define ORAN_CONFIG_NETHSPEED "eth_speed" + +// clang-format off +// TODO: PCI addr check +// TODO: ethernet addr check +#define ORAN_GLOBALPARAMS_DESC { \ + {ORAN_CONFIG_DPDK_DEVICES, "PCI addr of devices for DPDK\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ + {ORAN_CONFIG_IO_CORE, "DPDK Core used for IO\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=4, TYPE_INT, 0}, \ + {ORAN_CONFIG_WORKER_CORES, "CPU Cores to use for workers\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=NULL,TYPE_UINTARRAY, 0}, \ + {ORAN_CONFIG_DU_ADDR, "Ether addr of DU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ + {ORAN_CONFIG_RU_ADDR, "Ether addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ + {ORAN_CONFIG_MTU, "MTU of Eth interface\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=1500, TYPE_UINT, 0}, \ + {ORAN_CONFIG_FILE_PREFIX, "DPDK file-prefix\n", 0, .strptr=NULL, .defstrval="wls_0", TYPE_STRING, 0}, \ + {ORAN_CONFIG_NETHPERPORT, "number of links per port\n", 0, .uptr=NULL, .defuintval=1, TYPE_UINT, 0}, \ + {ORAN_CONFIG_NETHSPEED, "ethernet speed link\n", 0, .uptr=NULL, .defuintval=10, TYPE_UINT, 0}, \ +} +// clang-format on + +#define CONFIG_STRING_ORAN_FH "fh_config" + +#define ORAN_FH_CONFIG_TADV_CP_DL "Tadv_cp_dl" +#define ORAN_FH_CONFIG_T2A_CP_DL "T2a_cp_dl" +#define ORAN_FH_CONFIG_T2A_CP_UL "T2a_cp_ul" +#define ORAN_FH_CONFIG_T2A_UP "T2a_up" +#define ORAN_FH_CONFIG_TA3 "Ta3" +#define ORAN_FH_CONFIG_T1A_CP_DL "T1a_cp_dl" +#define ORAN_FH_CONFIG_T1A_CP_UL "T1a_cp_ul" +#define ORAN_FH_CONFIG_T1A_UP "T1a_up" +#define ORAN_FH_CONFIG_TA4 "Ta4" +#define ORAN_FH_CONFIG_CP_VLAN_TAG "cp_vlan_tag" +#define ORAN_FH_CONFIG_UP_VLAN_TAG "up_vlan_tag" + +#define ORAN_FH_HLP_CPLT " parameter of RU in list form (Min&Max, length 2!)\n" + +// clang-format off +#define ORAN_FH_DESC { \ + {ORAN_FH_CONFIG_TADV_CP_DL, "Tadv parameter of RU\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ + {ORAN_FH_CONFIG_T2A_CP_DL, "T2a_cp_dl" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ + {ORAN_FH_CONFIG_T2A_CP_UL, "T2a_cp_ul" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ + {ORAN_FH_CONFIG_T2A_UP, "T2a_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ + {ORAN_FH_CONFIG_TA3, "Ta3" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ + {ORAN_FH_CONFIG_T1A_CP_DL, "T1a_cp_dl" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ + {ORAN_FH_CONFIG_T1A_CP_UL, "T1a_cp_ul" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ + {ORAN_FH_CONFIG_T1A_UP, "T1a_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ + {ORAN_FH_CONFIG_TA4, "Ta4" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ + {ORAN_FH_CONFIG_CP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ + {ORAN_FH_CONFIG_UP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ +} +// clang-format on + +#define CONFIG_STRING_ORAN_RU "ru_config" + +#define ORAN_RU_CONFIG_IQWIDTH "iq_width" +#define ORAN_RU_CONFIG_IQWIDTH_PRACH "iq_width_prach" +#define ORAN_RU_CONFIG_FFT_SIZE "fft_size" + +// clang-format off +#define ORAN_RU_DESC {\ + {ORAN_RU_CONFIG_IQWIDTH, "sample IQ width (16=uncompressed)\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=16, TYPE_UINT8, 0}, \ + {ORAN_RU_CONFIG_IQWIDTH_PRACH, "PRACH sample IQ width (16=uncompressed)\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=16, TYPE_UINT8, 0}, \ + {ORAN_RU_CONFIG_FFT_SIZE, "Size of FFT at RU\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=12, TYPE_UINT8, 0}, \ +} +// clang-format on + +#define CONFIG_STRING_ORAN_PRACH "prach_config" + +#define ORAN_PRACH_CONFIG_EAXC_OFFSET "eAxC_offset" +#define ORAN_PRACH_CONFIG_KBAR "kbar" + +// clang-format off +#define ORAN_PRACH_DESC {\ + {ORAN_PRACH_CONFIG_EAXC_OFFSET, "RU's eAxC offset for PRACH\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=0, TYPE_UINT8, 0}, \ + {ORAN_PRACH_CONFIG_KBAR, "PRACH guard interval\n", 0, .uptr=NULL, .defuintval=4, TYPE_UINT, 0}, \ +} +// clang-format on + +#endif /* ORAN_PARAMS_H */ diff --git a/radio/fhi_72/oran.h b/radio/fhi_72/oran.h new file mode 100644 index 0000000000..c79bc88fa3 --- /dev/null +++ b/radio/fhi_72/oran.h @@ -0,0 +1,40 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _ORAN_H_ +#define _ORAN_H_ + +#include "shared_buffers.h" +#include "common_lib.h" +void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp); + +void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot); + +int transport_init(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params); + +typedef struct { + eth_state_t e; + shared_buffers buffers; + rru_config_msg_type_t last_msg; + int capabilities_sent; + void *oran_priv; +} oran_eth_state_t; +#endif /* _ORAN_H_ */ diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c new file mode 100644 index 0000000000..9624217c5d --- /dev/null +++ b/radio/fhi_72/oran_isolate.c @@ -0,0 +1,318 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include +#include +#include "common_lib.h" +#include "radio/ETHERNET/ethernet_lib.h" +#include "oran_isolate.h" +#include "oran-init.h" +#include "xran_fh_o_du.h" +#include "xran_sync_api.h" + +#include "common/utils/LOG/log.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "openair1/PHY/defs_gNB.h" +#include "common/utils/threadPool/thread-pool.h" +#include "oaioran.h" + +typedef struct { + eth_state_t e; + rru_config_msg_type_t last_msg; + int capabilities_sent; + void *oran_priv; +} oran_eth_state_t; + +notifiedFIFO_t oran_sync_fifo; + +int trx_oran_start(openair0_device *device) +{ + printf("ORAN: %s\n", __FUNCTION__); + + oran_eth_state_t *s = device->priv; + + // Start ORAN + if (xran_start(s->oran_priv) != 0) { + printf("%s:%d:%s: Start ORAN failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } else { + printf("Start ORAN. Done\n"); + } + return 0; +} + +void trx_oran_end(openair0_device *device) +{ + printf("ORAN: %s\n", __FUNCTION__); + oran_eth_state_t *s = device->priv; + xran_close(s->oran_priv); +} + +int trx_oran_stop(openair0_device *device) +{ + printf("ORAN: %s\n", __FUNCTION__); + oran_eth_state_t *s = device->priv; + xran_stop(s->oran_priv); + return (0); +} + +int trx_oran_set_freq(openair0_device *device, openair0_config_t *openair0_cfg) +{ + printf("ORAN: %s\n", __FUNCTION__); + return (0); +} + +int trx_oran_set_gains(openair0_device *device, openair0_config_t *openair0_cfg) +{ + printf("ORAN: %s\n", __FUNCTION__); + return (0); +} + +int trx_oran_get_stats(openair0_device *device) +{ + printf("ORAN: %s\n", __FUNCTION__); + return (0); +} + +int trx_oran_reset_stats(openair0_device *device) +{ + printf("ORAN: %s\n", __FUNCTION__); + return (0); +} + +int ethernet_tune(openair0_device *device, unsigned int option, int value) +{ + printf("ORAN: %s\n", __FUNCTION__); + return 0; +} + +int trx_oran_write_raw(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) +{ + printf("ORAN: %s\n", __FUNCTION__); + return 0; +} + +int trx_oran_read_raw(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) +{ + printf("ORAN: %s\n", __FUNCTION__); + return 0; +} + +char *msg_type(int t) +{ + static char *s[12] = { + "RAU_tick", + "RRU_capabilities", + "RRU_config", + "RRU_config_ok", + "RRU_start", + "RRU_stop", + "RRU_sync_ok", + "RRU_frame_resynch", + "RRU_MSG_max_num", + "RRU_check_sync", + "RRU_config_update", + "RRU_config_update_ok", + }; + + if (t < 0 || t > 11) + return "UNKNOWN"; + return s[t]; +} + +int trx_oran_ctlsend(openair0_device *device, void *msg, ssize_t msg_len) +{ + RRU_CONFIG_msg_t *rru_config_msg = msg; + oran_eth_state_t *s = device->priv; + + printf("ORAN: %s\n", __FUNCTION__); + + printf(" rru_config_msg->type %d [%s]\n", rru_config_msg->type, msg_type(rru_config_msg->type)); + + s->last_msg = rru_config_msg->type; + + return msg_len; +} + +int trx_oran_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len) +{ + RRU_CONFIG_msg_t *rru_config_msg = msg; + oran_eth_state_t *s = device->priv; + + printf("ORAN: %s\n", __FUNCTION__); + + if (s->last_msg == RAU_tick && s->capabilities_sent == 0) { + printf("ORAN ctrlrcv RRU_tick received and send capabilities hard coded\n"); + RRU_capabilities_t *cap; + rru_config_msg->type = RRU_capabilities; + rru_config_msg->len = sizeof(RRU_CONFIG_msg_t) - MAX_RRU_CONFIG_SIZE + sizeof(RRU_capabilities_t); + // Fill RRU capabilities (see openair1/PHY/defs_RU.h) + // For now they are hard coded - try to retreive the params from openari device + + cap = (RRU_capabilities_t *)&rru_config_msg->msg[0]; + cap->FH_fmt = OAI_IF4p5_only; + cap->num_bands = 1; + cap->band_list[0] = 78; + // cap->num_concurrent_bands = 1; component carriers + cap->nb_rx[0] = 1; // device->openair0_cfg->rx_num_channels; + cap->nb_tx[0] = 1; // device->openair0_cfg->tx_num_channels; + cap->max_pdschReferenceSignalPower[0] = -27; + cap->max_rxgain[0] = 90; + cap->N_RB_DL[0] = 106; + cap->N_RB_UL[0] = 106; + + s->capabilities_sent = 1; + + return rru_config_msg->len; + } + if (s->last_msg == RRU_config) { + printf("Oran RRU_config\n"); + rru_config_msg->type = RRU_config_ok; + } + return 0; +} + +void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) +{ + ru_info_t ru_info; + ru_info.nb_rx = ru->nb_rx; + ru_info.rxdataF = ru->common.rxdataF; + ru_info.prach_buf = ru->prach_rxsigF[0]; // index: [prach_oca][ant_id] + + RU_proc_t *proc = &ru->proc; + extern uint16_t sl_ahead; + int f, sl; + LOG_D(PHY, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]); + start_meas(&ru->rx_fhaul); + int ret = xran_fh_rx_read_slot(&ru_info, &f, &sl); + stop_meas(&ru->rx_fhaul); + LOG_D(PHY, "Read %d.%d rxdataF %p,%p\n", f, sl, ru_info.rxdataF[0], ru_info.rxdataF[1]); + if (ret != 0) { + printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX function \n", f, sl); + } + + proc->tti_rx = sl; + proc->frame_rx = f; + proc->tti_tx = (sl + sl_ahead) % 20; + proc->frame_tx = (sl > (19 - sl_ahead)) ? (f + 1) & 1023 : f; + + if (proc->first_rx == 0) { + if (proc->tti_rx != *slot) { + LOG_E(PHY, + "Received Time doesn't correspond to the time we think it is (slot mismatch, received %d.%d, expected %d.%d)\n", + proc->frame_rx, + proc->tti_rx, + *frame, + *slot); + *slot = proc->tti_rx; + } + + if (proc->frame_rx != *frame) { + LOG_E(PHY, + "Received Time doesn't correspond to the time we think it is (frame mismatch, %d.%d , expected %d.%d)\n", + proc->frame_rx, + proc->tti_rx, + *frame, + *slot); + *frame = proc->frame_rx; + } + } else { + proc->first_rx = 0; + LOG_I(PHY, "before adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx); + *frame = proc->frame_rx; + *slot = proc->tti_rx; + LOG_I(PHY, "After adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx); + } +} + +void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) +{ + start_meas(&ru->tx_fhaul); + ru_info_t ru_info; + ru_info.nb_tx = ru->nb_tx; + ru_info.txdataF_BF = ru->common.txdataF_BF; + // printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp); + + int ret = xran_fh_tx_send_slot(&ru_info, frame, slot, timestamp); + if (ret != 0) { + printf("ORAN: ORAN_fh_if4p5_south_out ERROR in TX function \n"); + } + stop_meas(&ru->tx_fhaul); +} + +void *get_internal_parameter(char *name) +{ + printf("ORAN: %s\n", __FUNCTION__); + + if (!strcmp(name, "fh_if4p5_south_in")) + return (void *)oran_fh_if4p5_south_in; + if (!strcmp(name, "fh_if4p5_south_out")) + return (void *)oran_fh_if4p5_south_out; + + return NULL; +} + +__attribute__((__visibility__("default"))) int transport_init(openair0_device *device, + openair0_config_t *openair0_cfg, + eth_params_t *eth_params) +{ + oran_eth_state_t *eth; + + device->Mod_id = 0; + device->transp_type = ETHERNET_TP; + device->trx_start_func = trx_oran_start; + device->trx_get_stats_func = trx_oran_get_stats; + device->trx_reset_stats_func = trx_oran_reset_stats; + device->trx_end_func = trx_oran_end; + device->trx_stop_func = trx_oran_stop; + device->trx_set_freq_func = trx_oran_set_freq; + device->trx_set_gains_func = trx_oran_set_gains; + + device->trx_write_func = trx_oran_write_raw; + device->trx_read_func = trx_oran_read_raw; + + device->trx_ctlsend_func = trx_oran_ctlsend; + device->trx_ctlrecv_func = trx_oran_ctlrecv; + + device->get_internal_parameter = get_internal_parameter; + + eth = (oran_eth_state_t *)calloc(1, sizeof(oran_eth_state_t)); + if (eth == NULL) { + AssertFatal(0 == 1, "out of memory\n"); + } + + eth->e.flags = ETH_RAW_IF4p5_MODE; + eth->e.compression = NO_COMPRESS; + eth->e.if_name = eth_params->local_if_name; + eth->oran_priv = NULL; // define_oran_pointer(); + device->priv = eth; + device->openair0_cfg = &openair0_cfg[0]; + + eth->last_msg = (rru_config_msg_type_t)-1; + + printf("ORAN: %s\n", __FUNCTION__); + + initNotifiedFIFO(&oran_sync_fifo); + eth->oran_priv = oai_oran_initialize(openair0_cfg); + AssertFatal(eth->oran_priv != NULL, "can not initialize fronthaul"); + // create message queues for ORAN sync + return 0; +} diff --git a/radio/fhi_72/oran_isolate.h b/radio/fhi_72/oran_isolate.h new file mode 100644 index 0000000000..7388f88f3b --- /dev/null +++ b/radio/fhi_72/oran_isolate.h @@ -0,0 +1,53 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _ORAN_ISOLATE_H_ +#define _ORAN_ISOLATE_H_ + +#include + +#include +#include + +#include "xran_fh_o_du.h" + +/* + * Structure added to bear the information needed from OAI RU + */ +typedef struct ru_info_s { + // Needed for UL + int nb_rx; + int32_t **rxdataF; + + // Needed for DL + int nb_tx; + int32_t **txdataF_BF; + + // Needed for Prach + int16_t **prach_buf; +} ru_info_t; + +int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot); +int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp); + +int compute_xran_statistics(); + +#endif /* _ORAN_ISOLATE_H_ */ diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf new file mode 100644 index 0000000000..3dfe311448 --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf @@ -0,0 +1,311 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); }); + + //nr_cellid = 12345678L; + nr_cellid = 1; + + ////////// Physical parameters: + + pdsch_AntennaPorts_XP = 2; + pusch_AntennaPorts = 4; + do_CSIRS = 1; + do_SRS = 0 ; + sib1_tda = 15; + + pdcch_ConfigSIB1 = ( + { + controlResourceSetZero = 11; #10; #thamizh change + searchSpaceZero = 0; + } + ); + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + # n_TimingAdvanceOffset = 0; +# downlinkConfigCommon + #frequencyInfoDL + # this is 3450.72 MHz (center frequency) + absoluteFrequencySSB = 666624; + dl_frequencyBand = 77; + # this is 3401.58 MHz + dl_absoluteFrequencyPointA = 663348; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 273; + #initialDownlinkBWP + #genericParameters + initialDLBWPlocationAndBandwidth = 1099; #38.101-1 Table 5.3.2-1 + # +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 11; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 77; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 273; + pMax = 23; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 1099; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 159; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 0; + preambleReceivedTargetPower = -100; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 7; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 2; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 5; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + +# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB + msg3_DeltaPreamble = 2; + p0_NominalWithGrant = -100; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 0; + p0_nominal = -96; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 0x1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 5; + nrofDownlinkSlots = 3; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 1; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = 0; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ( { ipv4 = "172.21.6.5"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + GNB_INTERFACE_NAME_FOR_NG_AMF = "eno8303"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.108/22"; + GNB_INTERFACE_NAME_FOR_NGU = "eno8303"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.108/22"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 80; + pucch_TargetSNRx10 = 200; + # dl_bler_target_upper=.35; + # dl_bler_target_lower=.15; + ul_bler_target_upper=.35; + ul_bler_target_lower=.15; + pusch_FailureThres = 100; + ulsch_max_frame_inactivity = 0; + ul_max_mcs = 25; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 130 + pucch0_dtx_threshold = 80; + pusch_dtx_threshold = -100; + max_ldpc_iterations = 10; +#thread_pool_size = 8; + tx_amp_backoff_dB = 3; + L1_rx_thread_core = 8; + L1_tx_thread_core = 10; # relevant after merge of l1_tx_thread + phase_compensation = 0; # needs to match O-RU configuration +} +); + +RUs = ( +{ + local_rf = "no"; + nb_tx = 4; + nb_rx = 4; + att_tx = 0 + att_rx = 0; + bands = [77]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + sf_extension = 0; + eNB_instances = [0]; + ru_thread_core = 6; + sl_ahead = 5; + ##beamforming 1x2 matrix: 1 layer x 2 antennas + bf_weights = [0x00007fff, 0x0000,0x00007fff, 0x0000]; + clock_src = "internal"; + tr_preference = "raw_if4p5"; # important: activate FHI7.2 + do_precoding = 0; # needs to match O-RU configuration +} +); + +rfsimulator : +{ + serveraddr = "server"; + serverport = "4043"; + options = (); #("saviq"); or/and "chanmod" + modelname = "AWGN"; + IQfile = "/tmp/rfsimulator.iqs"; +}; + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : { + global_log_level = "info"; + hw_log_level = "info"; + phy_log_level = "info"; + mac_log_level = "info"; + rlc_log_level = "info"; + pdcp_log_level = "info"; + rrc_log_level = "info"; + ngap_log_level = "info"; + f1ap_log_level = "info"; +}; + +fhi_72 = { + dpdk_devices = ("0000:31:06.0", "0000:31:06.1"); + io_core = 4; + worker_cores = (2); + du_addr = ("76:76:64:6e:00:01", "76:76:64:6e:00:01"); + ru_addr = ("98:ae:71:01:c5:eb", "98:ae:71:01:c5:eb"); + mtu = 9216; # check if xran uses this properly + fh_config = ({ + Tadv_cp_dl = 125; + T2a_cp_dl = (285, 429); # (min, max) + T2a_cp_ul = (285, 429); # (min, max) + T2a_up = (125, 428); # (min, max) + Ta3 = (130, 170); # (min, max) + T1a_cp_dl = (285, 470); # (min, max) + T1a_cp_ul = (285, 429); # (min, max) + T1a_up = (125, 350); # (min, max) + Ta4 = (110, 180); # (min, max) + ru_config = { + iq_width = 9; + iq_width_prach = 9; + fft_size = 12; + }; + prach_config = { + eAxC_offset = 4; + }; + }); +}; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf new file mode 100644 index 0000000000..bc532c6a23 --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf @@ -0,0 +1,304 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); }); + + nr_cellid = 1; + + ////////// Physical parameters: + + pdsch_AntennaPorts_XP = 2; + pusch_AntennaPorts = 2; + do_CSIRS = 1; + do_SRS = 0 ; + sib1_tda = 15; + + pdcch_ConfigSIB1 = ( + { + controlResourceSetZero = 11; + searchSpaceZero = 0; + } + ); + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + # n_TimingAdvanceOffset = 0; +# downlinkConfigCommon + #frequencyInfoDL + # this is 3450.72 MHz (center frequency) + absoluteFrequencySSB = 630048; + dl_frequencyBand = 78; + # this is 3401.58 MHz + dl_absoluteFrequencyPointA = 626772; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 273; + #initialDownlinkBWP + #genericParameters + initialDLBWPlocationAndBandwidth = 1099; #38.101-1 Table 5.3.2-1 + # +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 11; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 273; + pMax = 23; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 1099; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 151; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 0; + preambleReceivedTargetPower = -100; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 7; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 3; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 5; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + +# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB + msg3_DeltaPreamble = 2; + p0_NominalWithGrant = -96; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 0; + p0_nominal = -96; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 0x1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = 10; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ( { ipv4 = "172.21.6.5"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + GNB_INTERFACE_NAME_FOR_NG_AMF = "eno8303"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.108/22"; + GNB_INTERFACE_NAME_FOR_NGU = "eno8303"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.108/22"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 100; + pucch_TargetSNRx10 = 230; + dl_bler_target_upper=.35; + dl_bler_target_lower=.15; + ul_bler_target_upper=.35; + ul_bler_target_lower=.15; + pusch_FailureThres = 100; + ul_max_mcs = 28; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 100; + pucch0_dtx_threshold = 80; + pusch_dtx_threshold = 10; + max_ldpc_iterations = 10; + tx_amp_backoff_dB = 20; # needs to match O-RU configuration + L1_rx_thread_core = 8; + L1_tx_thread_core = 10; # relevant after merge of l1_tx_thread + phase_compensation = 0; # needs to match O-RU configuration +} +); + +RUs = ( +{ + local_rf = "no"; + nb_tx = 4; + nb_rx = 2; + att_tx = 0 + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + sf_extension = 0; + eNB_instances = [0]; + ru_thread_core = 6; + sl_ahead = 10; + ##beamforming 1x2 matrix: 1 layer x 2 antennas + bf_weights = [0x00007fff, 0x0000,0x00007fff, 0x0000]; + #clock_src = "internal"; + sdr_addrs = "dummy --usecasefile /home/eurecom/raymond/usecase_du_3450_4ant.cfg --num_eth_vfs 2 --vf_addr_o_xu_a \"0000:31:06.0,0000:31:06.1\"" + clock_src = "internal"; + tr_preference = "raw_if4p5"; # important: activate FHI7.2 + do_precoding = 0; # needs to match O-RU configuration + +} +); + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : +{ + global_log_level ="info"; + hw_log_level ="info"; + phy_log_level ="info"; + mac_log_level ="info"; + rlc_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + ngap_log_level ="info"; + f1ap_log_level ="info"; +}; + +fhi_72 = { + dpdk_devices = ("0000:31:06.0", "0000:31:06.1"); + io_core = 4; + worker_cores = (2); + du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67"); + ru_addr = ("70:b3:d5:e1:5b:ff", "70:b3:d5:e1:5b:ff"); + mtu = 9216; + file_prefix = "fhi_72"; + fh_config = ({ + Tadv_cp_dl = 25; + T2a_cp_dl = (285, 429); + T2a_cp_ul = (285, 429); + T2a_up = (134, 1087); + Ta3 = (152, 160); + T1a_cp_dl = (258, 392); + T1a_cp_ul = (285, 300); + T1a_up = (155, 300); + Ta4 = (0, 200); + ru_config = { + iq_width = 9; + iq_width_prach = 9; + fft_size = 12; + }; + prach_config = { + eAxC_offset = 4; + }; + }); +}; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf new file mode 100644 index 0000000000..b8dbd61cbc --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf @@ -0,0 +1,303 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); }); + + nr_cellid = 1; + + ////////// Physical parameters: + + pdsch_AntennaPorts_XP = 2; + pusch_AntennaPorts = 4; + do_CSIRS = 1; + do_SRS = 0 ; + sib1_tda = 15; + + pdcch_ConfigSIB1 = ( + { + controlResourceSetZero = 11; + searchSpaceZero = 0; + } + ); + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + # n_TimingAdvanceOffset = 0; +# downlinkConfigCommon + #frequencyInfoDL + # this is 3450.72 MHz (center frequency) + absoluteFrequencySSB = 630048; + dl_frequencyBand = 78; + # this is 3401.58 MHz + dl_absoluteFrequencyPointA = 626772; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 273; + #initialDownlinkBWP + #genericParameters + initialDLBWPlocationAndBandwidth = 1099; #38.101-1 Table 5.3.2-1 + # +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 11; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 273; + pMax = 23; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 1099; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 159; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 22; + zeroCorrelationZoneConfig = 15; + preambleReceivedTargetPower = -104; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 7; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 2; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 5; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + +# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB + msg3_DeltaPreamble = 2; + p0_NominalWithGrant = -96; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 0; + p0_nominal = -96; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 0x1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 5; + nrofDownlinkSlots = 3; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 1; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = 0; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ( { ipv4 = "172.21.6.5"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + GNB_INTERFACE_NAME_FOR_NG_AMF = "eno8303"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.108/22"; + GNB_INTERFACE_NAME_FOR_NGU = "eno8303"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.108/22"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 200; + # dl_bler_target_upper=.35; + # dl_bler_target_lower=.15; + ul_bler_target_upper=.35; + ul_bler_target_lower=.15; + pusch_FailureThres = 100; + ulsch_max_frame_inactivity = 0; + ul_max_mcs = 25; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 130 + pucch0_dtx_threshold = 80; + pusch_dtx_threshold = 10; + max_ldpc_iterations = 10; + tx_amp_backoff_dB = 20; # needs to match O-RU configuration + L1_rx_thread_core = 8; + L1_tx_thread_core = 10; # relevant after merge of l1_tx_thread + phase_compensation = 1; # needs to match O-RU configuration +} +); + +RUs = ( +{ + local_rf = "no"; + nb_tx = 4; + nb_rx = 4; + att_tx = 0; # TODO relevant? + att_rx = 0; # TODO relevant? + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; # TODO relevant? + sf_extension = 0; # TODO relevant? + eNB_instances = [0]; # TODO is relevant? + ru_thread_core = 6; + sl_ahead = 5; + ##beamforming 1x2 matrix: 1 layer x 2 antennas + bf_weights = [0x00007fff, 0x0000,0x00007fff, 0x0000]; # necessary? + + tr_preference = "raw_if4p5"; # important: activate FHI7.2 + do_precoding = 0; # needs to match O-RU configuration + +} +); + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : +{ + global_log_level ="info"; + hw_log_level ="info"; + phy_log_level ="info"; + mac_log_level ="info"; + rlc_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + ngap_log_level ="info"; + f1ap_log_level ="info"; +}; + +fhi_72 = { + dpdk_devices = ("0000:31:06.0", "0000:31:06.1"); + io_core = 4; + worker_cores = (2); + du_addr = ("00:11:22:33:44:99", "00:11:22:33:44:99"); + ru_addr = ("e8:c7:4f:1e:c7:11", "e8:c7:4f:1e:c7:11"); + mtu = 1500; # check if xran uses this properly + fh_config = ({ + Tadv_cp_dl = 125; + T2a_cp_dl = (285, 429); # (min, max) + T2a_cp_ul = (285, 429); # (min, max) + T2a_up = (125, 428); # (min, max) + Ta3 = (130, 170); # (min, max) + T1a_cp_dl = (285, 429); # (min, max) + T1a_cp_ul = (285, 429); # (min, max) + T1a_up = (96, 196); # (min, max) + Ta4 = (110, 180); # (min, max) + ru_config = { + iq_width = 9; + iq_width_prach = 9; + fft_size = 12; + }; + prach_config = { + eAxC_offset = 4; + kbar = 0; + }; + }); +};