From 57c4633fd6c5e424fd855c959e2c3ca887a63294 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 21 Apr 2026 10:34:07 +0200 Subject: [PATCH 01/17] Take the long PRACH into account in queues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the commit ID: 03096dd4957a8254400c74f8a2999a11bf5d7439 Signed-off-by: Teodora Vladić --- openair1/PHY/NR_TRANSPORT/nr_prach.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index dc3cb1950d..efcc3dae1b 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -34,7 +34,8 @@ static bool drop_old_prach(const void *data, void *user) { const prach_item_t *p = data; const fsn_t *now = user; - const fsn_t t = {p->frame, p->slot, now->mu}; + // account for long PRACH over more than 1 slot + const fsn_t t = {p->frame, p->slot + p->num_slots - 1, now->mu}; bool drop = fsn_in_the_past(t, *now); if (drop) LOG_E(NR_PHY, "%4d.%2d PRACH job is in the past (%4d.%2d)\n", now->f, now->s, t.f, t.s); @@ -45,7 +46,8 @@ static bool get_current_prach(const void *data, void *user) { const prach_item_t *p = data; const fsn_t *now = user; - const fsn_t t = {p->frame, p->slot, now->mu}; + // account for long PRACH over more than 1 slot + const fsn_t t = {p->frame, p->slot + p->num_slots - 1, now->mu}; return fsn_equal(t, *now); } From 5b1f09faf1d1fa85053520002ec2e758aeec9a10 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Fri, 16 May 2025 13:27:27 +0000 Subject: [PATCH 02/17] feat(oran_fhlib_5g): update Findxran MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the Cmake find script for xran to detect K release (11.1.1). Signed-off-by: Teodora Vladić --- cmake_targets/tools/MODULES/Findxran.cmake | 8 +++++--- radio/fhi_72/CMakeLists.txt | 5 ++++- radio/fhi_72/mplane/CMakeLists.txt | 2 ++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/cmake_targets/tools/MODULES/Findxran.cmake b/cmake_targets/tools/MODULES/Findxran.cmake index efb6db13ea..5ef8748fea 100644 --- a/cmake_targets/tools/MODULES/Findxran.cmake +++ b/cmake_targets/tools/MODULES/Findxran.cmake @@ -4,9 +4,9 @@ # ------- # # 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 +# - oran_e_maintenance_release_v1.5 -> 5.1.6 +# - oran_f_release_v1.3 -> 6.1.4 +# - oran_k_release_v1.1 -> 11.1.1 # # Required options # ^^^^^^^^^^^^^^^^ @@ -88,6 +88,8 @@ if (xran_VERSION_STRING MATCHES "^oran_e_maintenance_release_v") string(REGEX REPLACE "oran_e_maintenance_release_v([0-9]+).([0-9]+)" "5.\\1.\\2" xran_VERSION ${xran_VERSION_STRING}) elseif(xran_VERSION_STRING MATCHES "^oran_f_release_v") string(REGEX REPLACE "oran_f_release_v([0-9]+).([0-9]+)" "6.\\1.\\2" xran_VERSION ${xran_VERSION_STRING}) +elseif(xran_VERSION_STRING MATCHES "^oran_k_release_v") + string(REGEX REPLACE "oran_k_release_v([0-9]+).([0-9]+)" "11.\\1.\\2" xran_VERSION ${xran_VERSION_STRING}) elseif(xran_VERSION_STRING MATCHES "^oran_bronze_release_v") string(REGEX REPLACE "oran_bronze_release_v([0-9]+).([0-9]+)" "2.\\1.\\2" xran_VERSION ${xran_VERSION_STRING}) else() diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index c9c51f7d80..9c77f6947e 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -19,14 +19,17 @@ add_library(oran_fhlib_5g MODULE ) set(F_VERSION 6.1.9) +set(K_VERSION 11.1.1) find_package(xran REQUIRED) if(xran_VERSION VERSION_GREATER_EQUAL 5 AND xran_VERSION VERSION_LESS 6) message(FATAL_ERROR "xran E release not supported starting from tag 2026.w08.\nPlease switch to F version ${F_VERSION}") elseif(xran_VERSION VERSION_EQUAL F_VERSION) target_compile_definitions(oran_fhlib_5g PRIVATE F_RELEASE) +elseif(xran_VERSION VERSION_EQUAL K_VERSION) + target_compile_definitions(oran_fhlib_5g PRIVATE K_RELEASE) else() - message(FATAL_ERROR "Found xran version ${xran_VERSION} but needed ${F_VERSION} (F release)") + message(FATAL_ERROR "Found xran version ${xran_VERSION} but needed ${F_VERSION} (F release) or ${K_VERSION} (K release)") endif() # Ignore xran-specific warning: we don't care/can't change the following warning, so suppress diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt index b25402cfce..4ed91cfb7a 100644 --- a/radio/fhi_72/mplane/CMakeLists.txt +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -12,6 +12,8 @@ if(xran_VERSION MATCHES "5.*") message(FATAL_ERROR "xran E release not supported starting from tag 2026.w08.\nPlease switch to F version ${F_VERSION}") elseif(xran_VERSION VERSION_EQUAL F_VERSION) target_compile_definitions(oran_fhlib_5g_mplane PRIVATE F_RELEASE) +elseif(xran_VERSION VERSION_EQUAL K_VERSION) + target_compile_definitions(oran_fhlib_5g_mplane PRIVATE K_RELEASE) endif() # Ignore xran-specific warning: we don't care/can't change the following warning, so suppress From e7c4d80a5d784e6cfd83b8298d45faf7c52a9ac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Fri, 3 Apr 2026 07:57:22 +0200 Subject: [PATCH 03/17] Create a cmake API for O_RAN SC xran forked repo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * create the xran forked repo as a cmake external project - easier to maintain and track the changes we applied to the original repo * add xran_DOWNLOAD option - clones and builds latest supported K release * update the FHI README for K release Signed-off-by: Teodora Vladić --- cmake_targets/tools/MODULES/Findxran.cmake | 21 +++------ doc/ORAN_FHI7.2_Tutorial.md | 32 +++++++++---- radio/fhi_72/CMakeLists.txt | 53 +++++++++++++++++++--- 3 files changed, 76 insertions(+), 30 deletions(-) diff --git a/cmake_targets/tools/MODULES/Findxran.cmake b/cmake_targets/tools/MODULES/Findxran.cmake index 5ef8748fea..56035c1426 100644 --- a/cmake_targets/tools/MODULES/Findxran.cmake +++ b/cmake_targets/tools/MODULES/Findxran.cmake @@ -46,13 +46,7 @@ # ``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() +set(CACHE{xran_LOCATION} TYPE PATH HELP "directory of XRAN library" VALUE "") find_path(xran_INCLUDE_DIR NAMES @@ -73,16 +67,14 @@ find_library(xran_LIBRARY PATH_SUFFIXES build api NO_DEFAULT_PATH ) -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}") +if(EXISTS ${xran_VERSION_FILE}) + file(STRINGS ${xran_VERSION_FILE} xran_VERSION_LINE REGEX "^#define[ \t]+VERSIONX[ \t]+\"[a-z_.0-9]+\"$") +else() + set(xran_VERSION_LINE "UNKNOWN") 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}") if (xran_VERSION_STRING MATCHES "^oran_e_maintenance_release_v") string(REGEX REPLACE "oran_e_maintenance_release_v([0-9]+).([0-9]+)" "5.\\1.\\2" xran_VERSION ${xran_VERSION_STRING}) @@ -93,9 +85,8 @@ elseif(xran_VERSION_STRING MATCHES "^oran_k_release_v") elseif(xran_VERSION_STRING MATCHES "^oran_bronze_release_v") string(REGEX REPLACE "oran_bronze_release_v([0-9]+).([0-9]+)" "2.\\1.\\2" xran_VERSION ${xran_VERSION_STRING}) else() - message(FATAL_ERROR "unrecognized xran version string: ${xran_VERSION_STRING}") + set(xran_VERSION "UNKNOWN") endif() -message(STATUS "Found xran release ${xran_VERSION_STRING} (v${xran_VERSION})") unset(xran_VERSION_LINE) unset(xran_VERSION_STRING) unset(xran_VERSION_FILE) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 051962fdb2..e766aacbe8 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -72,9 +72,9 @@ Tested libxran releases: | Vendor | |-----------------------------------------| | `oran_f_release_v1.0` | +| `oran_k_release_v1.0` | - -**Note**: The libxran driver of OAI identifies the above F release version as "6.1.0" (F is the sixth letter, then 1.0). +**Note**: The libxran driver of OAI identifies the above F release version as "6.1.0" (F is the sixth letter, then 1.0), and the above K release as "11.1.0". ### Configure your server @@ -274,7 +274,7 @@ timedatectl set-ntp false ### DPDK (Data Plane Development Kit) -Download DPDK version 20.11.9. +Download DPDK version 20.11.9 (F release) or 24.11.4 (K release). ```bash # on debian @@ -282,7 +282,8 @@ sudo apt install wget xz-utils libnuma-dev # on Fedora/RHEL sudo dnf install wget xz numactl-devel cd -wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz +wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz # F release +wget http://fast.dpdk.org/rel/dpdk-24.11.4.tar.xz # K release ``` #### DPDK Compilation and Installation @@ -290,10 +291,11 @@ wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz ```bash # Installing meson : it should pull ninja-build and compiler packages # on debian -sudo apt install meson +sudo apt install python3-pyelftools meson # on Fedora/RHEL -sudo dnf install meson -tar xvf dpdk-20.11.9.tar.xz && cd dpdk-stable-20.11.9 +sudo dnf install python3-pyelftools meson +tar xvf dpdk-20.11.9.tar.xz && cd dpdk-stable-20.11.9 # F release +tar xvf dpdk-24.11.4.tar.xz && cd dpdk-stable-24.11.4 # K release meson build ninja -C build @@ -359,7 +361,8 @@ pkg-config --libs libdpdk --static Go back to the version folder you used to build and install ``` -cd ~/dpdk-stable-20.11.9 +cd ~/dpdk-stable-20.11.9 # F release +cd ~/dpdk-stable-24.11.4 # K release sudo ninja deinstall -C build ``` @@ -384,6 +387,13 @@ git checkout oran_f_release_v1.0 git apply ~/openairinterface5g/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch ``` +#### K release +```bash +git clone https://github.com/openairinterface/o-du-phy.git ~/phy +cd ~/phy +git checkout # shall match a variable `K_VERSION` +``` + Compile the fronthaul interface library by calling `make` and the option `XRAN_LIB_SO=1` to have it build a shared object. Note that we provide two environment variables `RTE_SDK` for the path to the source tree of DPDK, and @@ -398,6 +408,7 @@ This feature is intended to enable experiments and future improvements on Arm sy cd ~/phy/fhi_lib/lib make clean WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=~/dpdk-stable-20.11.9/ XRAN_DIR=~/phy/fhi_lib make XRAN_LIB_SO=1 # F release +WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=~/dpdk-stable-24.11.4/ XRAN_DIR=~/phy/fhi_lib make XRAN_LIB_SO=1 # K release ... [AR] build/libxran.so ./build/libxran.so @@ -483,7 +494,10 @@ Note that you might also call cmake directly instead of using `build_oai`: ``` cd ~/openairinterface5g mkdir build && cd build +# build RAN after manually building xran F or K release cmake .. -GNinja -DOAI_FHI72=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib +# build RAN and xran K release automatically +cmake .. -GNinja -DOAI_FHI72=ON -Dxran_DOWNLOAD=ON ninja nr-softmodem oran_fhlib_5g params_libconfig ``` @@ -1636,6 +1650,8 @@ PKG_CONFIG_PATH=/opt/mplane-v2/lib/pkgconfig cmake .. -GNinja -DOAI_FHI72=ON -DO ninja nr-softmodem oran_fhlib_5g_mplane params_libconfig ``` +Note: instead of setting `xran_LOCATION`, feel free to use `xran_DOWNLOAD` option for automatic xran K release build. + ### Start the gNB Run the `nr-softmodem` from the build directory: ```bash diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index 9c77f6947e..9f09ba8168 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -21,15 +21,54 @@ add_library(oran_fhlib_5g MODULE set(F_VERSION 6.1.9) set(K_VERSION 11.1.1) -find_package(xran REQUIRED) -if(xran_VERSION VERSION_GREATER_EQUAL 5 AND xran_VERSION VERSION_LESS 6) - message(FATAL_ERROR "xran E release not supported starting from tag 2026.w08.\nPlease switch to F version ${F_VERSION}") -elseif(xran_VERSION VERSION_EQUAL F_VERSION) - target_compile_definitions(oran_fhlib_5g PRIVATE F_RELEASE) -elseif(xran_VERSION VERSION_EQUAL K_VERSION) +add_boolean_option(xran_DOWNLOAD OFF "Download and build xran library" OFF) + +find_package(xran) +if(xran_FOUND) + if(xran_VERSION VERSION_GREATER_EQUAL 5 AND xran_VERSION VERSION_LESS 6) + message(FATAL_ERROR "xran E release not supported starting from tag 2026.w08.\nPlease switch to F version ${F_VERSION} or K version ${K_VERSION}") + elseif(xran_VERSION VERSION_EQUAL F_VERSION) + target_compile_definitions(oran_fhlib_5g PRIVATE F_RELEASE) + elseif(xran_VERSION VERSION_EQUAL K_VERSION) + if(dpdk_VERSION VERSION_LESS 22) + message(FATAL_ERROR "DPDK version miniminum 22 required for K release, but found ${dpdk_VERSION}") + endif() + target_compile_definitions(oran_fhlib_5g PRIVATE K_RELEASE) + else() + message(FATAL_ERROR "Found xran version ${xran_VERSION} but needed ${F_VERSION} (F release) or ${K_VERSION} (K release)") + endif() +elseif(NOT xran_FOUND AND xran_DOWNLOAD) + if(dpdk_VERSION VERSION_LESS 22) + message(FATAL_ERROR "DPDK version miniminum 22 required for K release, but found ${dpdk_VERSION}") + endif() + include(ExternalProject) + set(xran_DIR "${CMAKE_BINARY_DIR}/.deps/src/extern_xran/fhi_lib/lib") + ExternalProject_Add(extern_xran + PREFIX ${CMAKE_BINARY_DIR}/.deps + GIT_REPOSITORY https://github.com/openairinterface/o-du-phy.git + GIT_TAG ${K_VERSION} + CONFIGURE_COMMAND "" # nothing to configure + BUILD_COMMAND cd fhi_lib/lib && WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=${dpdk_PREFIX} XRAN_DIR=.. make XRAN_LIB_SO=1 + BUILD_IN_SOURCE ON + INSTALL_COMMAND "" + BUILD_BYPRODUCTS ${xran_DIR}/build/libxran.so + ) + add_library(xran::xran UNKNOWN IMPORTED) + add_dependencies(xran::xran extern_xran) + # This is a workaround for the fact that included directories of an imported + # target should exist in the filesystem already at the configuration time. + # ref: https://gitlab.kitware.com/cmake/cmake/-/issues/15052 + file(MAKE_DIRECTORY "${xran_DIR}/api/") + file(MAKE_DIRECTORY "${xran_DIR}/build/") + set_target_properties(xran::xran PROPERTIES + IMPORTED_LOCATION "${xran_DIR}/build/libxran.so" + INTERFACE_INCLUDE_DIRECTORIES "${xran_DIR}/api/" + ) + message(STATUS "xran not found. Will clone and build automatically K release ${K_VERSION}") target_compile_definitions(oran_fhlib_5g PRIVATE K_RELEASE) else() - message(FATAL_ERROR "Found xran version ${xran_VERSION} but needed ${F_VERSION} (F release) or ${K_VERSION} (K release)") + message(FATAL_ERROR "could not find xran, and auto-download disabled. Update + xran_LOCATION, or set -Dxran_DOWNLOAD=ON") endif() # Ignore xran-specific warning: we don't care/can't change the following warning, so suppress From 77bb143b0406eae0f83298862017f398f445213a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Thu, 16 Apr 2026 16:34:58 +0200 Subject: [PATCH 04/17] feat(oran_fhlib_5g): Adapt oran_fhlib_5g for K release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapt the oran_fhlib_5g code to compile with xran K release. Like previously E and F, uses preprocessor directives to separate codes for different xran releases. Notes: 1. Release K of the FHI library supports many numerologies on one instance. As of now the integration supports only one numerology. 2. Several arrays in the xran interface are indexed by the numerology. It was ambiguous whether they were indexed by the actual numerology number or by the index of the relevant numerology within the numerology array. They are actually indexed by the numerology number so that when one is using only numerlogy 1 for example, he should only use perMu[1], fftSize[1], ... Signed-off-by: Teodora Vladić --- radio/fhi_72/oaioran.c | 92 ++++++++- radio/fhi_72/oaioran.h | 15 +- radio/fhi_72/oran-config.c | 393 +++++++++++++++++++++++++++++++------ radio/fhi_72/oran-init.c | 59 ++++-- 4 files changed, 471 insertions(+), 88 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index cca7d6190b..0604c7f649 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -35,7 +35,11 @@ // Declare variable useful for the send buffer function volatile bool first_call_set = false; -int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id); +int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id +#if defined K_RELEASE + , uint8_t mu +#endif + ); #include "common/utils/LOG/log.h" #ifndef USE_POLLING @@ -50,7 +54,11 @@ volatile oran_sync_info_t oran_sync_info = {0}; * timing information and unblock another thread in xran_fh_rx_read_slot() * through either a message queue, or writing in global memory with polling, on * a full slot boundary. */ -void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) +void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status +#if defined K_RELEASE + , uint8_t mu +#endif + ) { struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag; @@ -60,9 +68,13 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) const struct xran_fh_init *fh_init = get_xran_fh_init(); int num_ports = fh_init->xran_ports; +#if defined K_RELEASE + const int slots_in_sf = 1 << mu; +#elif defined F_RELEASE /* assuming all RUs have the same numerology */ const struct xran_fh_config *fh_cfg = get_xran_fh_config(0); const int slots_in_sf = 1 << fh_cfg->frame_conf.nNumerology; +#endif const int sf_in_frame = 10; static int rx_RU[XRAN_PORTS_NUM][160] = {0}; @@ -121,6 +133,9 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) info->tti = tti; info->sl = slot2; info->f = frame; +#if defined K_RELEASE + info->mu = mu; +#endif LOG_D(HW, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); atomic_fetch_add(&xran_queue_length, 1); pushNotifiedFIFO(&oran_sync_fifo, req); @@ -129,6 +144,9 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) oran_sync_info.tti = tti; oran_sync_info.sl = slot2; oran_sync_info.f = frame; +#if defined K_RELEASE + oran_sync_info.mu = mu; +#endif #endif } else LOG_E(HW, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); @@ -139,7 +157,11 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) /** @details Only used to unblock timing in oai_xran_fh_rx_callback() on first * call. */ -int oai_physide_dl_tti_call_back(void *param) +int oai_physide_dl_tti_call_back(void *param +#if defined K_RELEASE + , uint8_t mu +#endif + ) { if (!first_call_set) LOG_I(HW, "first_call set from phy cb\n"); @@ -152,7 +174,11 @@ int oai_physide_dl_tti_call_back(void *param) * @details Reads PRACH data from xran-specific buffers and, if I/Q compression * (bitwidth < 16 bits) is configured, uncompresses the data. Places PRACH data * in OAI buffer. */ -static int read_prach_data(ru_info_t *ru, int frame, int slot) +static int read_prach_data(ru_info_t *ru, int frame, int slot +#if defined K_RELEASE + , uint8_t mu +#endif + ) { /* calculate tti and subframe_id from frame, slot num */ int sym_idx = 0; @@ -174,7 +200,12 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) int prach_start_sym = prach_info.start_symbol; int prach_end_sym = prach_info.N_dur + prach_start_sym; struct xran_ru_config *ru_conf = &fh_cfg->ru_conf; + +#if defined K_RELEASE + int slots_per_frame = 10 << mu; +#elif defined F_RELEASE int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology; +#endif int tti = slots_per_frame * (frame) + (slot); int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports; @@ -330,10 +361,16 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) *slot = info->sl; *frame = info->f; +#if defined K_RELEASE + uint8_t mu = info->mu; +#endif delNotifiedFIFO_elt(res); #else *slot = oran_sync_info.sl; *frame = oran_sync_info.f; +#if defined K_RELEASE + uint8_t mu = oran_sync_info.mu; +#endif uint32_t tti_in = oran_sync_info.tti; static int last_slot = -1; @@ -350,14 +387,26 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) // return(0); struct xran_fh_config *fh_cfg = get_xran_fh_config(0); +#if defined K_RELEASE + int slots_per_frame = 10 << mu; +#elif defined F_RELEASE int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology; +#endif int tti = slots_per_frame * (*frame) + (*slot); - read_prach_data(ru, *frame, *slot); + read_prach_data(ru, *frame, *slot +#if defined K_RELEASE + , mu +#endif + ); const struct xran_fh_init *fh_init = get_xran_fh_init(); +#if defined K_RELEASE + int fftsize = 1 << fh_cfg->perMu[mu].nULFftSize; +#elif defined F_RELEASE int fftsize = 1 << fh_cfg->nULFftSize; +#endif int slot_offset_rxdata = 3 & (*slot); uint32_t slot_size = 4 * 14 * fftsize; @@ -397,7 +446,22 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) uint8_t *pData; struct xran_section_desc *p_sec_desc = NULL; struct xran_prb_elm *pRbElm = &pRbMap->prbMap[idxElm]; -#if defined F_RELEASE +#if defined K_RELEASE + 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 < num_totalRB * one_rb_size) + pData = bufs->dst[ant_id % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN] + .pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT] + .pData; + else { + p_sec_desc = &pRbElm->sec_desc[sym_idx]; + pData = p_sec_desc->pData; + } + numRB = num_totalRB; + startRB = start_totalRB; + { + { +#elif defined F_RELEASE // UP_nRBSize & UP_nRBStart are for DL U-plane only LOG_D(HW, "[%d.%d] idxElm[%d] startSym[%d]:numSym[%d] UP_startRB[%d]:UP_numRB[%d] sym_idx[%d] ant_id[%d] pRbElm->nRBStart[%d]:pRbElm->nRBSize[%d]\n", *frame, *slot, idxElm, pRbElm->nStartSymb, pRbElm->numSymb, pRbElm->UP_nRBStart, pRbElm->UP_nRBSize, sym_idx, ant_id, pRbElm->nRBStart, pRbElm->nRBSize); for (int idxDesc = 0; idxDesc < XRAN_MAX_FRAGMENT; idxDesc++) { @@ -516,7 +580,12 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) const struct xran_fh_init *fh_init = get_xran_fh_init(); const struct xran_fh_config *fh_cfg = get_xran_fh_config(0); +#if defined K_RELEASE + uint8_t mu_number = fh_cfg->mu_number[0]; + int fftsize = 1 << fh_cfg->perMu[mu_number].nDLFftSize; +#elif defined F_RELEASE int fftsize = 1 << fh_cfg->nDLFftSize; +#endif int nb_tx_per_ru = ru->nb_tx / fh_init->xran_ports; int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports; @@ -542,12 +611,15 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) LOG_D(HW, "pPrbMap->nPrbElm %d\n", pPrbMap->nPrbElm); for (uint32_t idxElm = 0; idxElm < pPrbMap->nPrbElm; idxElm++) { + struct xran_section_desc *p_sec_desc = NULL; struct xran_prb_elm *pRbElm = &pPrbMap->prbMap[idxElm]; int numRB, startRB; -#if defined F_RELEASE numRB = pRbElm->UP_nRBSize; startRB = pRbElm->UP_nRBStart; - struct xran_section_desc *p_sec_desc = &pRbElm->sec_desc[sym_idx][0]; +#if defined F_RELEASE + p_sec_desc = &pRbElm->sec_desc[sym_idx][0]; +#elif defined K_RELEASE + p_sec_desc = &pRbElm->sec_desc[sym_idx]; #endif LOG_D(HW, "pPrbMap[%d] : PRBstart %d nPRBs %d\n", idxElm, startRB, numRB); // For Liteon FR2 with RunSlotPrbMapBySymbolEnable xran_prb_map will have xran_prb_elm prbMap[14], each idxElm matches to sym_idx. @@ -644,9 +716,11 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) // => seems that the RUs don't check for E-bit #if defined F_RELEASE p_sec_desc = &p_prbMapElm->sec_desc[sym_idx][0]; +#elif defined K_RELEASE + p_sec_desc = &p_prbMapElm->sec_desc[sym_idx]; +#endif int16_t startRB = p_prbMapElm->UP_nRBStart; int16_t numRB = p_prbMapElm->UP_nRBSize; -#endif if (p_sec_desc == NULL) { printf("p_sec_desc == NULL\n"); diff --git a/radio/fhi_72/oaioran.h b/radio/fhi_72/oaioran.h index 3bb3a21970..cf9dfb70cb 100644 --- a/radio/fhi_72/oaioran.h +++ b/radio/fhi_72/oaioran.h @@ -12,11 +12,22 @@ typedef struct { uint32_t tti; uint32_t sl; uint32_t f; +#if defined K_RELEASE + uint8_t mu; +#endif } oran_sync_info_t; /** @brief xran callback for fronthaul RX, see xran_5g_fronthault_config(). */ -void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status); +void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status +#if defined K_RELEASE + , uint8_t mu +#endif + ); /** @brief xran callback for time alignment, see xran_reg_physide_cb(). */ -int oai_physide_dl_tti_call_back(void *param); +int oai_physide_dl_tti_call_back(void *param +#if defined K_RELEASE + , uint8_t mu +#endif + ); #endif /* OAIORAN_H */ diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c index 8da11c64ed..f2063b3b91 100644 --- a/radio/fhi_72/oran-config.c +++ b/radio/fhi_72/oran-config.c @@ -108,11 +108,9 @@ static void print_fh_init_io_cfg(const struct xran_io_cfg *io_cfg) io_cfg->one_vf_cu_plane); print_fh_eowd_cmn(io_cfg->id, &io_cfg->eowd_cmn[io_cfg->id]); printf("eowd_port (filled within xran library)\n"); -#if defined F_RELEASE printf("\ bbu_offload %d\n", io_cfg->bbu_offload); -#endif } static void print_fh_init_eaxcid_conf(const struct xran_eaxcid_config *eaxcid_conf) @@ -154,7 +152,13 @@ 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); +#if defined K_RELEASE + for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { + print_fh_init_eaxcid_conf(&fh_init->eAxCId_conf[o_xu_id]); + } +#elif defined F_RELEASE print_fh_init_eaxcid_conf(&fh_init->eAxCId_conf); +#endif printf("\ xran_ports %d\n\ dpdkBasebandFecMode %d\n\ @@ -173,34 +177,58 @@ void print_fh_init(const struct xran_fh_init *fh_init) printf("\ totalBfWeights %d\n", fh_init->totalBfWeights); -#if defined F_RELEASE printf("\ mlogxranenable %d\n\ dlCpProcBurst %d\n", fh_init->mlogxranenable, fh_init->dlCpProcBurst); -#endif } 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", +" +#if defined K_RELEASE +" 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\ + prachEaxcOffset %d\n\ + nprachformat %d\n\ + periodicity %d\n\ + startTime %d\n\ + suboffset %d\n\ + numSubCarriers %d\n\ + nRep %d\n", +#elif defined F_RELEASE +" 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", +#endif prach_conf->nPrachConfIdx, prach_conf->nPrachSubcSpacing, prach_conf->nPrachZeroCorrConf, @@ -215,33 +243,55 @@ static void print_prach_config(const struct xran_prach_config *prach_conf) prach_conf->numPrbc, prach_conf->timeOffset, prach_conf->freqOffset, - prach_conf->eAxC_offset); -#if defined F_RELEASE +#if defined K_RELEASE + prach_conf->prachEaxcOffset, + prach_conf->nprachformat, + prach_conf->periodicity, + prach_conf->startTime, + prach_conf->suboffset, + prach_conf->numSubCarriers, + prach_conf->nRep +#elif defined F_RELEASE + prach_conf->eAxC_offset +#endif + ); printf("\ nPrachConfIdxLTE %d\n", prach_conf->nPrachConfIdxLTE); -#endif } static void print_srs_config(const struct xran_srs_config *srs_conf) { printf("\ srs_config:\n\ - symbMask %04x\n\ - eAxC_offset %d\n", + symbMask %04x\n" +#if defined K_RELEASE +" srsEaxcOffset %d\n", +#elif defined F_RELEASE +" eAxC_offset %d\n", +#endif srs_conf->symbMask, - srs_conf->eAxC_offset); +#if defined K_RELEASE + srs_conf->srsEaxcOffset +#elif defined F_RELEASE + srs_conf->eAxC_offset +#endif + ); } 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", + nFrameDuplexType %s\n" +#if defined F_RELEASE +" nNumerology %d\n" +#endif +" nTddPeriod %d\n", frame_conf->nFrameDuplexType == XRAN_TDD ? "TDD" : "FDD", +#if defined F_RELEASE frame_conf->nNumerology, +#endif frame_conf->nTddPeriod); for (int i = 0; i < frame_conf->nTddPeriod; ++i) { printf(" sSlotConfig[%d]: ", i); @@ -253,7 +303,11 @@ static void print_frame_config(const struct xran_frame_config *frame_conf) } } -static void print_ru_config(const struct xran_ru_config *ru_conf) +static void print_ru_config( +#if defined K_RELEASE + uint8_t mu_number, +#endif + const struct xran_ru_config *ru_conf) { printf("\ ru_config:\n\ @@ -263,9 +317,13 @@ static void print_ru_config(const struct xran_ru_config *ru_conf) iqWidth %d\n\ compMeth %d\n\ iqWidth_PRACH %d\n\ - compMeth_PRACH %d\n\ - fftSize %d\n\ - byteOrder %s\n\ + compMeth_PRACH %d\n" +#if defined K_RELEASE +" fftSize[mu_number] %d\n" +#elif defined F_RELEASE +" fftSize %d\n" +#endif +" byteOrder %s\n\ iqOrder %s\n\ xran_max_frame %d\n", ru_conf->xranTech == XRAN_RAN_5GNR ? "NR" : "LTE", @@ -275,27 +333,106 @@ static void print_ru_config(const struct xran_ru_config *ru_conf) ru_conf->compMeth, ru_conf->iqWidth_PRACH, ru_conf->compMeth_PRACH, +#if defined K_RELEASE + ru_conf->fftSize[mu_number], +#elif defined F_RELEASE ru_conf->fftSize, +#endif 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); } +#if defined K_RELEASE +void print_fh_per_mu_cfg(const struct xran_fh_per_mu_cfg *perMu) +{ + printf("\ + perMu:\n\ + nDLBandwidth %d\n\ + nULBandwidth %d\n", + perMu->nDLBandwidth, + perMu->nULBandwidth); + + print_prach_config(&perMu->prach_conf); + + printf("\ + freqOffset %d\n\ + nDLFftSize %d\n\ + nULFftSize %d\n\ + eaxcOffset %d\n\ + nDLRBs %d\n\ + nULRBs %d\n\ + 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\ + prachEnable %d\n\ + prachConfigIndex %d\n\ + prachConfigIndexLTE %d\n\ + nbIotUlScs %d\n\ + adv_tx_time %d\n", + perMu->freqOffset, + perMu->nDLFftSize, + perMu->nULFftSize, + perMu->eaxcOffset, + perMu->nDLRBs, + perMu->nULRBs, + perMu->Tadv_cp_dl, + perMu->T2a_min_cp_dl, + perMu->T2a_max_cp_dl, + perMu->T2a_min_cp_ul, + perMu->T2a_max_cp_ul, + perMu->T2a_min_up, + perMu->T2a_max_up, + perMu->Ta3_min, + perMu->Ta3_max, + perMu->T1a_min_cp_dl, + perMu->T1a_max_cp_dl, + perMu->T1a_min_cp_ul, + perMu->T1a_max_cp_ul, + perMu->T1a_min_up, + perMu->T1a_max_up, + perMu->Ta4_min, + perMu->Ta4_max, + perMu->prachEnable, + perMu->prachConfigIndex, + perMu->prachConfigIndexLTE, + perMu->nbIotUlScs, + perMu->adv_tx_time); +} +#endif + 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\ + nAntElmTRx %d\n" +#if defined F_RELEASE +" nDLFftSize %d\n\ nULFftSize %d\n\ nDLRBs %d\n\ - nULRBs %d\n\ - nDLAbsFrePointA %d\n\ + nULRBs %d\n" +#endif +" nDLAbsFrePointA %d\n\ nULAbsFrePointA %d\n\ nDLCenterFreqARFCN %d\n\ nULCenterFreqARFCN %d\n\ @@ -307,17 +444,23 @@ void print_fh_config(const struct xran_fh_config *fh_config) fh_config->neAxc, fh_config->neAxcUl, fh_config->nAntElmTRx, +#if defined F_RELEASE fh_config->nDLFftSize, fh_config->nULFftSize, fh_config->nDLRBs, fh_config->nULRBs, +#endif fh_config->nDLAbsFrePointA, fh_config->nULAbsFrePointA, fh_config->nDLCenterFreqARFCN, fh_config->nULCenterFreqARFCN, fh_config->ttiCb, fh_config->ttiCbParam); - +#if defined K_RELEASE + uint8_t mu_number = fh_config->mu_number[0]; + print_fh_per_mu_cfg(&fh_config->perMu[mu_number]); +#endif +#if defined F_RELEASE printf("\ Tadv_cp_dl %d\n\ T2a_min_cp_dl %d\n\ @@ -353,45 +496,49 @@ void print_fh_config(const struct xran_fh_config *fh_config) fh_config->T1a_max_up, fh_config->Ta4_min, fh_config->Ta4_max); - +#endif printf("\ - enableCP %d\n\ - prachEnable %d\n\ - srsEnable %d\n\ + enableCP %d\n" +#if defined F_RELEASE +" prachEnable %d\n" +#endif +" 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, +#if defined F_RELEASE fh_config->prachEnable, +#endif 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); -#if defined F_RELEASE printf("\ srsEnableCp %d\n\ SrsDelaySym %d\n", fh_config->srsEnableCp, fh_config->SrsDelaySym); -#endif +#if defined F_RELEASE print_prach_config(&fh_config->prach_conf); +#endif print_srs_config(&fh_config->srs_conf); print_frame_config(&fh_config->frame_conf); - print_ru_config(&fh_config->ru_conf); + print_ru_config( +#if defined K_RELEASE + mu_number, +#endif + &fh_config->ru_conf); printf("\ bbdev_enc %p\n\ @@ -413,7 +560,6 @@ void print_fh_config(const struct xran_fh_config *fh_config) fh_config->max_sections_per_slot, fh_config->max_sections_per_symbol); -#if defined F_RELEASE printf("\ RunSlotPrbMapBySymbolEnable %d\n\ dssEnable %d\n\ @@ -422,6 +568,15 @@ void print_fh_config(const struct xran_fh_config *fh_config) fh_config->RunSlotPrbMapBySymbolEnable, fh_config->dssEnable, fh_config->dssPeriod); + +#if defined K_RELEASE + printf("\ + numMUs %d\n\ + mu_number[0] %d\n\ + nNumerology[0] %d\n", + fh_config->numMUs, + fh_config->mu_number[0], + fh_config->nNumerology[0]); #endif } @@ -536,9 +691,7 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in /* eCPRI OWDM per port variables for O-DU; this parameter is filled within xran library */ // eowd_port[0][XRAN_VF_MAX] -#if defined F_RELEASE io_cfg->bbu_offload = 0; // enable packet handling on BBU cores -#endif return true; } @@ -575,7 +728,7 @@ static bool set_fh_eaxcid_conf_mplane(struct xran_eaxcid_config *eaxcid_conf, en return true; } #else -static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat) +static bool __attribute__((unused)) set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat) { /* CUS specification, section 3.1.3.1.6 DU_port_ID - used to differentiate processing units at O-DU (e.g., different baseband cards). @@ -666,8 +819,16 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus)) return false; +#if defined K_RELEASE + for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { + if (!set_fh_eaxcid_conf_mplane(&fh_init->eAxCId_conf[o_xu_id], xran_cat, ru_session_list)) + return false; + } +#elif defined F_RELEASE if (!set_fh_eaxcid_conf_mplane(&fh_init->eAxCId_conf, xran_cat, ru_session_list)) return false; +#endif + /* maximum transmission unit (MTU) is the size of the largest protocol data unit (PDU) that can be communicated in a single xRAN network layer transaction. Based on the MTU size, xran calculates the number of DL fragments (nPrbElm) needed for transmission of one symbol. */ @@ -691,8 +852,16 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus)) return false; +#if defined K_RELEASE + for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { + if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf[o_xu_id], xran_cat)) + return false; + } +#elif defined F_RELEASE if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, xran_cat)) return false; +#endif + /* maximum transmission unit (MTU) is the size of the largest protocol data unit (PDU) that can be communicated in a single xRAN network layer transaction. Based on the MTU size, xran calculates the number of DL fragments (nPrbElm) needed for transmission of one symbol. */ @@ -736,11 +905,9 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr); fh_init->totalBfWeights = 0; // only used if id = O_RU (for emulation); C-plane extension types; section 5.4.6 of CUS spec -#if defined F_RELEASE fh_init->mlogxranenable = 0; // enable mlog; 0 -> disabled fh_init->dlCpProcBurst = 0; /* 1 -> DL CP processing will be done on single symbol, 0 -> DL CP processing will be spread across all allowed symbols and multiple cores to reduce burstiness */ -#endif return true; } @@ -780,9 +947,7 @@ static bool set_fh_prach_config(void *mplane_api, prach_config->numPrbc = 0; prach_config->timeOffset = 0; prach_config->freqOffset = 0; -#if defined F_RELEASE prach_config->nPrachConfIdxLTE = 0; // used only if DSS enabled and technology is XRAN_RAN_LTE -#endif /* xran defines PDSCH eAxC IDs as [0...Ntx-1]; xran defines PUSCH eAxC IDs as [0...Nrx-1]; @@ -791,10 +956,18 @@ static bool set_fh_prach_config(void *mplane_api, Please note that this approach only applies to the RUs that support this functionality, e.g. LITEON RU. */ #ifdef OAI_MPLANE xran_mplane_t *xran_mplane = (xran_mplane_t *)mplane_api; +#if defined F_RELEASE prach_config->eAxC_offset = xran_mplane->prach_offset; +#elif defined K_RELEASE + prach_config->prachEaxcOffset = xran_mplane->prach_offset; +#endif #else const paramdef_t *pd = gpd(prachp, nprach, ORAN_PRACH_CONFIG_EAXC_OFFSET); +#if defined F_RELEASE prach_config->eAxC_offset = pd->paramflags & PARAMFLAG_PARAMSET ? *pd->u8ptr : max_num_ant; +#elif defined K_RELEASE + prach_config->prachEaxcOffset = pd->paramflags & PARAMFLAG_PARAMSET ? *pd->u8ptr : max_num_ant; +#endif #endif g_kbar = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_KBAR)->uptr; @@ -806,8 +979,10 @@ static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame { const split7_config_t *s7cfg = &oai0->split7; frame_config->nFrameDuplexType = oai0->duplex_mode == duplex_mode_TDD ? XRAN_TDD : XRAN_FDD; // Frame Duplex type: 0 -> FDD, 1 -> TDD +#if defined F_RELEASE frame_config->nNumerology = oai0->nr_scs_for_raster; /* 0 -> 15kHz, 1 -> 30kHz, 2 -> 60kHz 3 -> 120kHz, 4 -> 240kHz */ +#endif if (frame_config->nFrameDuplexType == XRAN_FDD) return true; @@ -824,7 +999,11 @@ static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame return true; } -static bool set_fh_ru_config(void *mplane_api, const paramdef_t *rup, uint16_t fftSize, int nru, enum xran_category xran_cat, struct xran_ru_config *ru_config) +static bool set_fh_ru_config(void *mplane_api, const paramdef_t *rup, uint16_t fftSize, int nru, enum xran_category xran_cat +#if defined K_RELEASE + , uint8_t mu_number +#endif + , struct xran_ru_config *ru_config) { ru_config->xranTech = XRAN_RAN_5GNR; // 5GNR or LTE ru_config->xranCat = xran_cat; // mode: Catergory A or Category B @@ -843,7 +1022,11 @@ static bool set_fh_ru_config(void *mplane_api, const paramdef_t *rup, uint16_t f ru_config->compMeth_PRACH = ru_config->iqWidth_PRACH < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method for PRACH AssertFatal(fftSize > 0, "FFT size cannot be 0\n"); +#if defined K_RELEASE + ru_config->fftSize[mu_number] = fftSize; // FFT Size +#elif defined F_RELEASE ru_config->fftSize = fftSize; // FFT Size +#endif ru_config->byteOrder = XRAN_NE_BE_BYTE_ORDER; // order of bytes in int16_t in buffer; big or little endian ru_config->iqOrder = XRAN_I_Q_ORDER; // order of IQs in the buffer ru_config->xran_max_frame = 0; // max frame number supported; if not specified, default of 1023 is used @@ -866,6 +1049,69 @@ static bool set_maxmin_pd(const paramdef_t *pd, int num, const char *name, uint1 return true; } +#if defined K_RELEASE +static bool set_fh_per_mu_cfg(void *mplane_api, int ru_idx, int num_rus, const openair0_config_t *oai0, struct xran_fh_per_mu_cfg *perMu) +{ + char aprefix[MAX_OPTNAME_SIZE] = {0}; + + paramdef_t FHconfigs[] = ORAN_FH_DESC; + paramlist_def_t FH_ConfigList = {CONFIG_STRING_ORAN_FH}; + 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 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); + int 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; + } + + perMu->nDLBandwidth = 0; // Carrier bandwidth for in MHz. Value: 5->400. Not used in K release + perMu->nULBandwidth = 0; // Carrier bandwidth for in MHz. Value: 5->400. Not used in K release + if (!set_fh_prach_config(mplane_api, oai0, RTE_MAX(oai0->tx_num_channels / num_rus, oai0->rx_num_channels / num_rus), prachp, nprach, &perMu->prach_conf)) + return false; + perMu->freqOffset = 0; + + perMu->nDLFftSize = oai0->split7.fftSize; // DL FFT size + perMu->nULFftSize = oai0->split7.fftSize; // UL FFT size + + perMu->eaxcOffset = 0; // Starting value of Eaxc for PDSCH, PUSCH packets (Absolute value) of this numerology. Should be unique across all numerologies for the RU + + perMu->nDLRBs = oai0->num_rb_dl; // DL PRB + perMu->nULRBs = oai0->num_rb_dl; // UL PRB + + /* DU delay profile */ + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_DL, &perMu->T1a_min_cp_dl, &perMu->T1a_max_cp_dl)) // E - min not used in xran, max yes; F - both min and max are used in xran + return false; + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_UL, &perMu->T1a_min_cp_ul, &perMu->T1a_max_cp_ul)) // both E and F - min not used in xran, max yes + return false; + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_UP, &perMu->T1a_min_up, &perMu->T1a_max_up)) // both E and F - min not used in xran, max yes + return false; + if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA4, &perMu->Ta4_min, &perMu->Ta4_max)) // both E and F - min not used in xran, max yes + return false; + + perMu->prachEnable = 1; // enable PRACH + const split7_config_t *s7cfg = &oai0->split7; + perMu->prachConfigIndex = s7cfg->prach_index; // TS36.211 - Table 5.7.1-2 : PRACH Configuration Index + perMu->prachConfigIndexLTE = 0; // PRACH Configuration Index for LTE in dss case + + perMu->nbIotUlScs = XRAN_NBIOT_UL_SCS_15; /* Applicable only for NB-IOT (mu=4). NBIOT supports asymmetric SCS usage in + downlink and uplink directions. xran library will use this parameter to derive + slot-duration for UL NB-IOT: + XRAN_NBIOT_UL_SCS_15: slot-duration=1ms + XRAN_NBIOT_UL_SCS_3_75: slot-duration=2ms */ + perMu->adv_tx_time = 0; // Time by which the packet should be transmitted in advance (microseconds) + return true; +} + static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_category xran_cat, 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"); @@ -915,10 +1161,12 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c fh_config->neAxc = RTE_MAX(oai0->tx_num_channels / num_rus, oai0->rx_num_channels / num_rus); // number of eAxc supported on one CC = max(PDSCH, PUSCH) fh_config->neAxcUl = 0; // number of eAxc supported on one CC for UL direction = PUSCH; used only if XRAN_CATEGORY_B fh_config->nAntElmTRx = 0; // number of antenna elements for TX and RX = SRS; used only if XRAN_CATEGORY_B +#if defined F_RELEASE fh_config->nDLFftSize = oai0->split7.fftSize; // DL FFT size; not used in xran fh_config->nULFftSize = oai0->split7.fftSize; // UL FFT size; not used in xran fh_config->nDLRBs = oai0->num_rb_dl; // DL PRB; used in oaioran.c/oran-init.c; not used in xran, neither in E nor in F release fh_config->nULRBs = oai0->num_rb_dl; // UL PRB; used in oaioran.c/oran-init.c; in xran E release not used so the patch fixes it, but in xran F release this value is properly used +#endif fh_config->nDLAbsFrePointA = 0; // Abs Freq Point A of the Carrier Center Frequency for in KHz Value; not used in xran fh_config->nULAbsFrePointA = 0; // Abs Freq Point A of the Carrier Center Frequency for in KHz Value; not used in xran fh_config->nDLCenterFreqARFCN = 0; // center frequency for DL in NR-ARFCN; not used in xran @@ -926,6 +1174,13 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c fh_config->ttiCb = NULL; // check tti_to_phy_cb(), tx_cp_dl_cb() and tx_cp_ul_cb => first_call fh_config->ttiCbParam = NULL; // check tti_to_phy_cb(), tx_cp_dl_cb() and tx_cp_ul_cb => first_call +#if defined K_RELEASE + uint8_t mu_number = oai0->nr_scs_for_raster; + if(!set_fh_per_mu_cfg(mplane_api, ru_idx, num_rus, oai0, &fh_config->perMu[mu_number])) + return false; +#endif + +#if defined F_RELEASE /* DU delay profile */ if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_DL, &fh_config->T1a_min_cp_dl, &fh_config->T1a_max_cp_dl)) // E - min not used in xran, max yes; F - both min and max are used in xran return false; @@ -935,9 +1190,12 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c return false; if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA4, &fh_config->Ta4_min, &fh_config->Ta4_max)) // both E and F - min not used in xran, max yes return false; +#endif fh_config->enableCP = 1; // enable C-plane +#if defined F_RELEASE fh_config->prachEnable = 1; // enable PRACH +#endif fh_config->srsEnable = 0; // enable SRS; used only if XRAN_CATEGORY_B // For LiteOn E release, no need to take care of prach eAxC_offset. xran lib is hacked to handle it. #if defined F_RELEASE @@ -946,22 +1204,35 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c #endif fh_config->puschMaskEnable = 0; // enable PUSCH mask; only used if id = O_RU fh_config->puschMaskSlot = 0; // specific which slot PUSCH channel masked; only used if id = O_RU +#if defined K_RELEASE + fh_config->csirsEnable = 0; // enable CSI-RS (Cat B specific) +#elif defined F_RELEASE fh_config->cp_vlan_tag = 0; // C-plane VLAN tag; not used in xran; needed for M-plane fh_config->up_vlan_tag = 0; // U-plane VLAN tag; not used in xran; needed for M-plane +#endif fh_config->debugStop = 0; // enable auto stop; only used if id = O_RU fh_config->debugStopCount = 0; // enable auto stop after number of Tx packets; not used in xran fh_config->DynamicSectionEna = 0; // enable dynamic C-Plane section allocation fh_config->GPS_Alpha = 0; // refers to alpha as defined in section 9.7.2 of ORAN spec. this value should be alpha*(1/1.2288ns), range 0 - 1e7 (ns); offset_nsec = (pConf->GPS_Beta - offset_sec * 100) * 1e7 + pConf->GPS_Alpha fh_config->GPS_Beta = 0; // beta value as defined in section 9.7.2 of ORAN spec. range -32767 ~ +32767; offset_sec = pConf->GPS_Beta / 100 - +#if defined K_RELEASE + fh_config->numMUs = 1; + fh_config->nNumerology[0] = mu_number; /* 0 -> 15kHz, 1 -> 30kHz, 2 -> 60kHz, 3 -> 120kHz, 4 -> 240kHz */ +#elif defined F_RELEASE if (!set_fh_prach_config(mplane_api, oai0, fh_config->neAxc, prachp, nprach, &fh_config->prach_conf)) return false; +#endif + /* SRS only used if XRAN_CATEGORY_B Note: srs_config->eAxC_offset >= prach_config->eAxC_offset + PRACH */ // fh_config->srs_conf = {0}; if (!set_fh_frame_config(oai0, &fh_config->frame_conf)) return false; - if (!set_fh_ru_config(mplane_api, rup, oai0->split7.prach_fftSize, nru, xran_cat, &fh_config->ru_conf)) + if (!set_fh_ru_config(mplane_api, rup, oai0->split7.prach_fftSize, nru, xran_cat +#if defined K_RELEASE + , mu_number +#endif + , &fh_config->ru_conf)) return false; fh_config->bbdev_enc = NULL; // call back to poll BBDev encoder @@ -985,13 +1256,11 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c fh_config->max_sections_per_slot = 0; // not used in xran fh_config->max_sections_per_symbol = 0; // not used in xran -#if defined F_RELEASE fh_config->RunSlotPrbMapBySymbolEnable = *gpd(fhp, nfh, ORAN_CONFIG_CP_MULTISECTION)->uptr; // enable PRB mapping by symbol with multisection fh_config->dssEnable = 0; // enable DSS (extension-9) fh_config->dssPeriod = 0; // DSS pattern period for LTE/NR // fh_config->technology[XRAN_MAX_DSS_PERIODICITY] // technology array represents slot is LTE(0)/NR(1); used only if DSS enabled -#endif return true; } diff --git a/radio/fhi_72/oran-init.c b/radio/fhi_72/oran-init.c index ec5f6d0f8c..b575309635 100644 --- a/radio/fhi_72/oran-init.c +++ b/radio/fhi_72/oran-init.c @@ -81,7 +81,12 @@ static struct xran_prb_map get_xran_prb_map(const struct xran_fh_config *f, cons e->nStartSymb = start_sym; e->numSymb = num_sym; e->nRBStart = 0; +#if defined K_RELEASE + uint8_t mu_number = f->mu_number[0]; + e->nRBSize = (dir == XRAN_DIR_DL) ? f->perMu[mu_number].nDLRBs : f->perMu[mu_number].nULRBs; +#elif defined F_RELEASE e->nRBSize = (dir == XRAN_DIR_DL) ? f->nDLRBs : f->nULRBs; +#endif e->nBeamIndex = 0; e->compMethod = f->ru_conf.compMeth; e->iqWidth = f->ru_conf.iqWidth; @@ -182,10 +187,8 @@ static void oran_allocate_cplane_buffers(void *instHandle, struct xran_flat_buffer buf[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN], uint32_t ant, uint32_t sect, - #if defined F_RELEASE uint32_t mtu, const struct xran_fh_config *fh_config, - #endif uint32_t size_of_prb_map, oran_cplane_prb_config *prb_conf) { @@ -219,20 +222,27 @@ static void oran_allocate_cplane_buffers(void *instHandle, // get mixed slot map if in TDD and in mixed slot if (prb_conf->nTddPeriod != 0 && (j % prb_conf->nTddPeriod) == prb_conf->mixed_slot_index) src = &prb_conf->mixedSlotMap; -#if defined F_RELEASE if (fh_config->RunSlotPrbMapBySymbolEnable) { +#if defined K_RELEASE + uint8_t mu_number = fh_config->mu_number[0]; + xran_init_PrbMap_by_symbol_from_cfg(src, ptr, mtu, fh_config->perMu[mu_number].nDLRBs); +#elif defined F_RELEASE xran_init_PrbMap_by_symbol_from_cfg(src, ptr, mtu, fh_config->nDLRBs); +#endif } else { xran_init_PrbMap_from_cfg(src, ptr, mtu); } -#endif } } printf("xran_bm_allocate_buffer() hInstance %p poolIdx %u count %u\n", instHandle, poolPrb, count1); } /* callback not actively used */ -static void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status) +static void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status +#if defined K_RELEASE + , uint8_t mu +#endif + ) { rte_pause(); } @@ -241,9 +251,7 @@ static void oran_allocate_buffers(void *handle, int xran_inst, int num_sectors, oran_port_instance_t *portInstances, - #if defined F_RELEASE uint32_t mtu, - #endif const struct xran_fh_config *fh_config) { AssertFatal(num_sectors == 1, "only support one sector at the moment\n"); @@ -297,38 +305,40 @@ static void oran_allocate_buffers(void *handle, .mixedSlotMap = ulPmMixed, }; -#if defined F_RELEASE uint32_t numPrbElm = (fh_config->RunSlotPrbMapBySymbolEnable) ? XRAN_NUM_OF_SYMBOL_PER_SLOT : xran_get_num_prb_elm(&dlPm, mtu); uint32_t size_of_prb_map = sizeof(struct xran_prb_map) + sizeof(struct xran_prb_elm) * (numPrbElm); -#endif // PDSCH +#if defined K_RELEASE + const uint32_t txBufSize = get_nSW_ToFpga_FTH_TxBufferLen(fh_config->nNumerology[0], fh_config->max_sections_per_slot); +#elif defined F_RELEASE const uint32_t txBufSize = get_nSW_ToFpga_FTH_TxBufferLen(fh_config->frame_conf.nNumerology, fh_config->max_sections_per_slot); +#endif oran_allocate_uplane_buffers(pi->instanceHandle, bl->src, bl->bufs.tx, xran_max_antenna_nr, txBufSize); oran_allocate_cplane_buffers(pi->instanceHandle, bl->srccp, bl->bufs.tx_prbmap, xran_max_antenna_nr, xran_max_sections_per_slot, - #if defined F_RELEASE mtu, fh_config, - #endif size_of_prb_map, &dlConf); // PUSCH +#if defined K_RELEASE + const uint32_t rxBufSize = get_nFpgaToSW_FTH_RxBufferLen(fh_config->nNumerology[0]); +#elif defined F_RELEASE const uint32_t rxBufSize = get_nFpgaToSW_FTH_RxBufferLen(fh_config->frame_conf.nNumerology); +#endif oran_allocate_uplane_buffers(pi->instanceHandle, bl->dst, bl->bufs.rx, xran_max_antenna_nr, rxBufSize); oran_allocate_cplane_buffers(pi->instanceHandle, bl->dstcp, bl->bufs.rx_prbmap, xran_max_antenna_nr, xran_max_sections_per_slot, - #if defined F_RELEASE mtu, fh_config, - #endif size_of_prb_map, &ulConf); @@ -364,8 +374,13 @@ static void oran_allocate_buffers(void *handle, } } +#if defined K_RELEASE + xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->pusch_tag, fh_config->nNumerology[0]); + xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag, fh_config->nNumerology[0]); +#elif defined F_RELEASE xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->pusch_tag); xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag); +#endif } int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_config *xran_fh_config) @@ -394,20 +409,34 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi struct xran_cb_tag tag = {.cellId = sector, .oXuId = o_xu_id}; pi->prach_tag = tag; pi->pusch_tag = tag; -#if defined F_RELEASE oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]); -#endif +#if defined K_RELEASE + if ((xret = xran_timingsource_reg_tticb(gxran_handle, oai_physide_dl_tti_call_back, NULL, 10, XRAN_CB_TTI)) != XRAN_STATUS_SUCCESS) { + printf("xran_timingsource_reg_tticb failed %d\n", xret); + exit(-1); + } +#elif defined F_RELEASE 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); } +#endif // retrieve and store prach duration +#if defined K_RELEASE + uint8_t mu = xran_fh_config[o_xu_id].nNumerology[0]; + uint8_t idx = xran_fh_config[o_xu_id].perMu[mu].prach_conf.nPrachConfIdx; +#elif defined F_RELEASE uint8_t idx = xran_fh_config[o_xu_id].prach_conf.nPrachConfIdx; +#endif const struct xran_frame_config *fc = &xran_fh_config[o_xu_id].frame_conf; g_prach_info[o_xu_id] = get_nr_prach_occasion_info_from_index(idx, +#if defined K_RELEASE + mu > 2 ? FR2 : FR1, +#elif defined F_RELEASE fc->nNumerology > 2 ? FR2 : FR1, +#endif fc->nFrameDuplexType == XRAN_FDD ? duplex_mode_FDD : duplex_mode_TDD); } From 7b7afae05b6a9aa5d68b6bdacfb5174139ee796a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Thu, 16 Apr 2026 17:15:21 +0200 Subject: [PATCH 05/17] feat(oran_fhlib_5g): Changes to run K release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initialize leak detector * Fill IO config field holding the number of mbufs to be allocated * Allocate and fill `activeMUs` in the FH config * Start timing source, worker thread and activate CCs upon starting the FH * Fill `mu_number[0]` in FH config * Invert trx_oran end and stop * Set `neAxcUl` * Delete duplicated oran_eth_state_t struct definition * gxran_handle is an array which length is equal to the number of RUs * Fill BBDev VF token in fh_init Co-authored-by: Romain Beurdouche Signed-off-by: Teodora Vladić --- executables/nr-softmodem.c | 6 +-- radio/fhi_72/oaioran.c | 8 +++- radio/fhi_72/oran-config.c | 75 ++++++++++++++++++++++++++++++++++++- radio/fhi_72/oran-init.c | 36 ++++++++++++++++-- radio/fhi_72/oran-init.h | 6 ++- radio/fhi_72/oran.h | 7 ---- radio/fhi_72/oran_isolate.c | 74 +++++++++++++++++++++++++++++++++++- 7 files changed, 191 insertions(+), 21 deletions(-) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 1198e5bd02..59f8b96194 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -358,9 +358,6 @@ int stop_L1(module_id_t gnb_id) if (RC.nb_nr_L1_inst > 0) stop_gNB(RC.nb_nr_L1_inst); - if (RC.nb_RU > 0) - stop_RU(RC.nb_RU); - /* stop trx devices, multiple carrier currently not supported by RU */ if (ru->rfdevice.trx_get_stats_func) { ru->rfdevice.trx_get_stats_func(&ru->rfdevice); @@ -378,6 +375,9 @@ int stop_L1(module_id_t gnb_id) LOG_I(GNB_APP, "turned off RU ifdevice\n"); } + if (RC.nb_RU > 0) + stop_RU(RC.nb_RU); + /* release memory used by the RU/gNB threads (incomplete), after all * threads have been stopped (they partially use the same memory) */ for (int inst = 0; inst < RC.nb_RU; inst++) { diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 0604c7f649..886173cb67 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -535,8 +535,12 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) } // 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++) { + for (int o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { +#if defined F_RELEASE + if ((*frame & 0x7f) == 0 && *slot == 0 && xran_get_common_counters(gxran_handle, &x_counters[0]) == XRAN_STATUS_SUCCESS) { +#elif defined K_RELEASE + if ((*frame & 0x7f) == 0 && *slot == 0 && xran_get_common_counters(gxran_handle[o_xu_id], &x_counters[o_xu_id]) == XRAN_STATUS_SUCCESS) { +#endif LOG_I(HW, "[%s%d][rx %7ld pps %7ld kbps %7ld][tx %7ld pps %7ld kbps %7ld][Total Msgs_Rcvd %ld]\n", "o-du ", diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c index f2063b3b91..ca7c1527dd 100644 --- a/radio/fhi_72/oran-config.c +++ b/radio/fhi_72/oran-config.c @@ -592,10 +592,8 @@ static void get_u128_mask(const paramdef_t *pd, uint64_t *u0t63, uint64_t *u64t1 } } -#if defined F_RELEASE char bbdev_dev[32] = ""; char bbdev_vfio_vf_token[64] = ""; -#endif static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, int nump, const int num_rus) { @@ -666,6 +664,10 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in io_cfg->io_sleep = 0; // enable sleep on PMD cores; 0 -> no sleep io_cfg->nEthLinePerPort = *gpd(fhip, nump, ORAN_CONFIG_NETHPERPORT)->uptr; // 1, 2, 3 total number of links per O-RU (Fronthaul Ethernet link) io_cfg->nEthLineSpeed = *gpd(fhip, nump, ORAN_CONFIG_NETHSPEED)->uptr; // 10G,25G,40G,100G speed of Physical connection on O-RU +#if defined K_RELEASE + io_cfg->num_mbuf_alloc = NUM_MBUFS; // number of mbuf allocated by DPDK (optimal is n = (2^q - 1)) + io_cfg->num_mbuf_vf_alloc = NUM_MBUFS_VF; // number of mbuf allocated by DPDK (optimal is n = (2^q - 1)) +#endif io_cfg->one_vf_cu_plane = (io_cfg->num_vfs == num_rus); // C-plane and U-plane use one VF /* eCPRI One-Way Delay Measurements common settings for O-DU and O-RU; @@ -696,6 +698,48 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in return true; } +#if defined K_RELEASE +static bool set_fh_bbdev_params(struct xran_fh_init *fh_init) +{ + struct xran_io_cfg *io_cfg = &fh_init->io_cfg; + io_cfg->bbdev_dev[0] = NULL; // BBDev dev name; max devices = 1 + fh_init->dpdkVfioVfToken = NULL; // BBDev dev token; max devices = 1 + char *shlibversion = NULL; // version of the LDPC coding library + paramdef_t LoaderParams_shlibversion[] = {{"shlibversion", NULL, 0, .strptr = &shlibversion, .defstrval = NULL, TYPE_STRING, 0, NULL}}; + config_get(config_get_if(), LoaderParams_shlibversion, sizeofArray(LoaderParams_shlibversion), "loader.ldpc"); + if (shlibversion != NULL && strncmp(shlibversion, "_aal", 4) == 0) { + uint32_t is_t2 = 0; // If not 0 then include the BBDEV device in the EAL init for FHI + char *dpdk_dev = NULL; // PCI address of the card + char *vfio_vf_token = NULL; // vfio token for the bbdev card + paramdef_t LoaderParams[] = { + {"is_t2", NULL, 0, .uptr = &is_t2, .defuintval = 0, TYPE_UINT, 0, NULL}, + {"dpdk_dev", NULL, 0, .strptr = &dpdk_dev, .defstrval = NULL, TYPE_STRING, 0, NULL}, + {"vfio_vf_token", NULL, 0, .strptr = &vfio_vf_token, .defstrval = NULL, TYPE_STRING, 0, NULL} + }; + config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_aal"); + + if (!is_t2) { + AssertFatal(dpdk_dev!=NULL, "nrLDPC_coding_aal.dpdk_dev was not provided"); + snprintf(&bbdev_dev[0], sizeof(bbdev_dev), "%s", dpdk_dev); + io_cfg->bbdev_dev[0] = &bbdev_dev[0]; // BBDev dev name; max devices = 1 + if(vfio_vf_token != NULL) { + snprintf(&bbdev_vfio_vf_token[0], sizeof(bbdev_vfio_vf_token), "%s", vfio_vf_token); + fh_init->dpdkVfioVfToken = &bbdev_vfio_vf_token[0]; // BBDev dev token; max devices = 1 + } else { + fh_init->dpdkVfioVfToken = NULL; // BBDev dev token; max devices = 1 + } + io_cfg->bbdev_mode = XRAN_BBDEV_MODE_HW_ON; // DPDK for BBDev + } else { + io_cfg->bbdev_mode = XRAN_BBDEV_NOT_USED; // DPDK for BBDev + } + } else { + io_cfg->bbdev_mode = XRAN_BBDEV_NOT_USED; // DPDK for BBDev + } + + return true; +} +#endif + #ifdef OAI_MPLANE static bool set_fh_eaxcid_conf_mplane(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat, const ru_session_list_t *ru_session_list) { @@ -820,6 +864,8 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus)) return false; #if defined K_RELEASE + if (!set_fh_bbdev_params(fh_init)) + return false; for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { if (!set_fh_eaxcid_conf_mplane(&fh_init->eAxCId_conf[o_xu_id], xran_cat, ru_session_list)) return false; @@ -853,6 +899,8 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus)) return false; #if defined K_RELEASE + if (!set_fh_bbdev_params(fh_init)) + return false; for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf[o_xu_id], xran_cat)) return false; @@ -1112,6 +1160,19 @@ static bool set_fh_per_mu_cfg(void *mplane_api, int ru_idx, int num_rus, const o return true; } +xran_active_numerologies_per_tti activeMUs; + +static bool set_activeMUs(xran_active_numerologies_per_tti *p_activeMUs, uint8_t mu) +{ + for (int i = 0; i < XRAN_N_FE_BUF_LEN; i++) { + for (int j = 0; j < XRAN_MAX_NUM_MU; j++) { + p_activeMUs->numerology[i][j] = j == mu; + } + } + return true; +} +#endif + static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_category xran_cat, 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"); @@ -1159,7 +1220,11 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c fh_config->sector_id = 0; // Band sector ID for FH; not used in xran fh_config->nCC = 1; // number of Component carriers supported on FH; M-plane info fh_config->neAxc = RTE_MAX(oai0->tx_num_channels / num_rus, oai0->rx_num_channels / num_rus); // number of eAxc supported on one CC = max(PDSCH, PUSCH) +#if defined K_RELEASE + fh_config->neAxcUl = oai0->rx_num_channels / num_rus; // number of eAxc supported on one CC for UL direction = PUSCH +#elif defined F_RELEASE fh_config->neAxcUl = 0; // number of eAxc supported on one CC for UL direction = PUSCH; used only if XRAN_CATEGORY_B +#endif fh_config->nAntElmTRx = 0; // number of antenna elements for TX and RX = SRS; used only if XRAN_CATEGORY_B #if defined F_RELEASE fh_config->nDLFftSize = oai0->split7.fftSize; // DL FFT size; not used in xran @@ -1217,6 +1282,7 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c fh_config->GPS_Beta = 0; // beta value as defined in section 9.7.2 of ORAN spec. range -32767 ~ +32767; offset_sec = pConf->GPS_Beta / 100 #if defined K_RELEASE fh_config->numMUs = 1; + fh_config->mu_number[0] = mu_number; /* 0 -> 15kHz, 1 -> 30kHz, 2 -> 60kHz, 3 -> 120kHz, 4 -> 240kHz */ fh_config->nNumerology[0] = mu_number; /* 0 -> 15kHz, 1 -> 30kHz, 2 -> 60kHz, 3 -> 120kHz, 4 -> 240kHz */ #elif defined F_RELEASE if (!set_fh_prach_config(mplane_api, oai0, fh_config->neAxc, prachp, nprach, &fh_config->prach_conf)) @@ -1261,6 +1327,11 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c fh_config->dssEnable = 0; // enable DSS (extension-9) fh_config->dssPeriod = 0; // DSS pattern period for LTE/NR // fh_config->technology[XRAN_MAX_DSS_PERIODICITY] // technology array represents slot is LTE(0)/NR(1); used only if DSS enabled +#if defined K_RELEASE + if (!set_activeMUs(&activeMUs, oai0->nr_scs_for_raster)) + return false; + fh_config->activeMUs = &activeMUs; +#endif return true; } diff --git a/radio/fhi_72/oran-init.c b/radio/fhi_72/oran-init.c index b575309635..315347e7d1 100644 --- a/radio/fhi_72/oran-init.c +++ b/radio/fhi_72/oran-init.c @@ -27,7 +27,11 @@ // 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]; +#if defined F_RELEASE void *gxran_handle; +#elif defined K_RELEASE +void *gxran_handle[XRAN_PORTS_NUM]; +#endif static struct xran_fh_init g_fh_init = {0}; static struct xran_fh_config g_fh_config[XRAN_PORTS_NUM] = {0}; @@ -383,21 +387,44 @@ static void oran_allocate_buffers(void *handle, #endif } -int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_config *xran_fh_config) +void *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_config *xran_fh_config) { int32_t xret = 0; +#if defined K_RELEASE + xran_mem_mgr_leak_detector_init(); +#endif + print_fh_init(xran_fh_init); +#if defined F_RELEASE xret = xran_init(0, NULL, xran_fh_init, NULL, &gxran_handle); +#elif defined K_RELEASE + xret = xran_init(0, NULL, xran_fh_init, NULL, gxran_handle); +#endif if (xret != XRAN_STATUS_SUCCESS) { printf("xran_init failed %d\n", xret); exit(-1); } +#if defined K_RELEASE + for (int32_t o_xu_id = 0; o_xu_id < xran_fh_init->xran_ports; o_xu_id++) { + if (gxran_handle[o_xu_id] == NULL) { + printf("xran_init for RU%d failed\n", o_xu_id); + exit(-1); + } else { + printf("RU%d handle = %p\n", o_xu_id, gxran_handle[o_xu_id]); + } + } +#endif + /** process all the O-RU|O-DU for use case */ for (int32_t o_xu_id = 0; o_xu_id < xran_fh_init->xran_ports; o_xu_id++) { print_fh_config(&xran_fh_config[o_xu_id]); +#if defined F_RELEASE xret = xran_open(gxran_handle, &xran_fh_config[o_xu_id]); +#elif defined K_RELEASE + xret = xran_open(gxran_handle[o_xu_id], &xran_fh_config[o_xu_id]); +#endif if (xret != XRAN_STATUS_SUCCESS) { printf("xran_open failed %d\n", xret); exit(-1); @@ -409,14 +436,15 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi struct xran_cb_tag tag = {.cellId = sector, .oXuId = o_xu_id}; pi->prach_tag = tag; pi->pusch_tag = tag; - oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]); #if defined K_RELEASE - if ((xret = xran_timingsource_reg_tticb(gxran_handle, oai_physide_dl_tti_call_back, NULL, 10, XRAN_CB_TTI)) != XRAN_STATUS_SUCCESS) { + oran_allocate_buffers(gxran_handle[0], o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]); + if ((xret = xran_timingsource_reg_tticb(NULL, oai_physide_dl_tti_call_back, NULL, 10, XRAN_CB_TTI)) != XRAN_STATUS_SUCCESS) { printf("xran_timingsource_reg_tticb failed %d\n", xret); exit(-1); } #elif defined F_RELEASE + oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &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); @@ -445,7 +473,7 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi memcpy(&g_fh_init, xran_fh_init, sizeof(*xran_fh_init)); memcpy(&g_fh_config, xran_fh_config, sizeof(*xran_fh_config) * xran_fh_init->xran_ports); - return (void *)gxran_handle; + return gxran_handle; } oran_buf_list_t *get_xran_buffers(uint32_t port_id) diff --git a/radio/fhi_72/oran-init.h b/radio/fhi_72/oran-init.h index ed1076d483..135e2cf307 100644 --- a/radio/fhi_72/oran-init.h +++ b/radio/fhi_72/oran-init.h @@ -41,9 +41,13 @@ typedef struct oran_port_instance_t { } oran_port_instance_t; extern struct xran_fh_config gxran_fh_config[XRAN_PORTS_NUM]; +#if defined F_RELEASE extern void *gxran_handle; +#elif defined K_RELEASE +extern void *gxran_handle[XRAN_PORTS_NUM]; +#endif -int *oai_oran_initialize(struct xran_fh_init *fh_init, struct xran_fh_config *fh_config); +void *oai_oran_initialize(struct xran_fh_init *fh_init, struct xran_fh_config *fh_config); oran_buf_list_t *get_xran_buffers(uint32_t port_id); struct xran_fh_init *get_xran_fh_init(void); diff --git a/radio/fhi_72/oran.h b/radio/fhi_72/oran.h index 08d7574f49..d322f35f1e 100644 --- a/radio/fhi_72/oran.h +++ b/radio/fhi_72/oran.h @@ -13,11 +13,4 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot); int transport_init(openair0_device_t *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 index 3a670f5f7f..fd6ba98232 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -34,6 +34,8 @@ typedef struct { int capabilities_sent; void *oran_priv; void *mplane_priv; + uint32_t nCC; + uint32_t num_ports; } oran_eth_state_t; notifiedFIFO_t oran_sync_fifo; @@ -45,12 +47,53 @@ int trx_oran_start(openair0_device_t *device) oran_eth_state_t *s = device->priv; // Start ORAN +#if defined K_RELEASE + if (xran_timingsource_start() != 0) { + printf("%s:%d:%s: Start timing source failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } else { + printf("Start timing source. Done\n"); + } + + if (xran_start_worker_threads() != 0) { + printf("%s:%d:%s: Start worker thread failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } else { + printf("Start worker thread. Done\n"); + } + + xran_mem_mgr_leak_detector_display(0); +#endif + +#if defined F_RELEASE 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"); } +#elif defined K_RELEASE + for (int32_t port_id = 0; port_id < s->num_ports; port_id++) { + if (xran_start(((void **)s->oran_priv)[port_id]) != 0) { + printf("%s:%d:%s: Start ORAN port ID %d failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__, port_id); + exit(1); + } + } +#endif + + printf("Start ORAN. Done\n"); + +#if defined K_RELEASE + for (int32_t cc_id = 0; cc_id < s->nCC; cc_id++) { + for (int32_t port_id = 0; port_id < s->num_ports; port_id++) { + if (xran_activate_cc(port_id, cc_id) != 0) { + printf("%s:%d:%s: Activate CC failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } else { + printf("Activate CC. Done\n"); + } + } + } +#endif + return 0; } @@ -58,14 +101,39 @@ void trx_oran_end(openair0_device_t *device) { printf("ORAN: %s\n", __FUNCTION__); oran_eth_state_t *s = device->priv; +#if defined K_RELEASE + xran_shutdown(s->oran_priv); +#endif xran_close(s->oran_priv); +#if defined K_RELEASE + xran_cleanup(); + xran_mem_mgr_leak_detector_destroy(); +#endif } int trx_oran_stop(openair0_device_t *device) { printf("ORAN: %s\n", __FUNCTION__); oran_eth_state_t *s = device->priv; + +#if defined K_RELEASE + for (int32_t cc_id = 0; cc_id < s->nCC; cc_id++) { + for (int32_t port_id = 0; port_id < s->num_ports; port_id++) { + xran_deactivate_cc(port_id, cc_id); + } + } + + xran_timingsource_stop(); +#endif + +#if defined F_RELEASE xran_stop(s->oran_priv); +#elif defined K_RELEASE + for (int32_t port_id = 0; port_id < s->num_ports; port_id++) { + xran_stop(((void **)s->oran_priv)[port_id]); + } +#endif + #ifdef OAI_MPLANE printf("[MPLANE] Stopping M-plane.\n"); disconnect_mplane(s->mplane_priv); @@ -395,6 +463,8 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device_t eth->e.compression = NO_COMPRESS; eth->e.if_name = eth_params->local_if_name; eth->last_msg = (rru_config_msg_type_t)-1; + eth->nCC = fh_config->nCC; + eth->num_ports = fh_init.xran_ports; device->transp_type = ETHERNET_TP; device->trx_start_func = trx_oran_start; From ba4239653eb5c61cd41669b1bb281089b38874d5 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Fri, 13 Jun 2025 07:01:20 +0000 Subject: [PATCH 06/17] feat(oran_fhlib_5g): RX error counters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit K releases added RX error counters This commits adds a printing of these counters with LOG_I Signed-off-by: Teodora Vladić --- radio/fhi_72/oaioran.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 886173cb67..b075397c1e 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -561,6 +561,18 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) x_counters[o_xu_id].rx_pusch_packets[rxant], rxant, x_counters[o_xu_id].rx_prach_packets[rxant]); +#if defined K_RELEASE + LOG_I(HW, + "[%s%d][drop errors %7d ecpri errors %7d cp errors %7d up errors %7d pusch errors %7d prach errors %7d]\n", + "o_du", + o_xu_id, + x_counters[o_xu_id].rx_err_drop, + x_counters[o_xu_id].rx_err_ecpri, + x_counters[o_xu_id].rx_err_cp, + x_counters[o_xu_id].rx_err_up, + x_counters[o_xu_id].rx_err_pusch, + x_counters[o_xu_id].rx_err_prach); +#endif 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]) From 6b665a851e32af8ca35ac88ff194f230bbf1a351 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Tue, 14 Apr 2026 15:17:34 +0200 Subject: [PATCH 07/17] Process PUSCH packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xran K release introduces a new parameter nRxPkt describing the fragmentation of Rx symbols. Co-authored-by: Teodora Vladić Signed-off-by: Teodora Vladić --- radio/fhi_72/oaioran.c | 74 ++++++++++++++++++++++++++++++---------- radio/fhi_72/oaioran.h | 6 ++-- radio/fhi_72/oran-init.c | 3 ++ 3 files changed, 63 insertions(+), 20 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index b075397c1e..4284912c3d 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -44,6 +44,7 @@ int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id #ifndef USE_POLLING extern notifiedFIFO_t oran_sync_fifo; +#define MAX_QUEUE_LENGTH_NO_JUMP 3 atomic_int xran_queue_length = 0; #else volatile oran_sync_info_t oran_sync_info = {0}; @@ -135,6 +136,21 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status info->f = frame; #if defined K_RELEASE info->mu = mu; + + for (int ru_idx = 0; ru_idx < num_ports; ru_idx++) { + oran_buf_list_t *bufs = get_xran_buffers(ru_idx); + struct xran_fh_config *fh_config = get_xran_fh_config(ru_idx); + for (uint16_t cc_id = 0; cc_id < 1 /* fh_config->nCC */; cc_id++) { // OAI does not support multiple CC yet. + for(uint32_t ant_id = 0; ant_id < fh_config->neAxc; ant_id++) { + struct xran_prb_map *pRbMap = (struct xran_prb_map *)bufs->dstcp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; + AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMap == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id); + for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) { + info->nRxPkt[cc_id][ant_id][sym_id] = pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt; + pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt = 0; + } + } + } + } #endif LOG_D(HW, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); atomic_fetch_add(&xran_queue_length, 1); @@ -146,6 +162,19 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status oran_sync_info.f = frame; #if defined K_RELEASE oran_sync_info.mu = mu; + + oran_buf_list_t *bufs = get_xran_buffers(ru_id); + struct xran_fh_config *fh_config = get_xran_fh_config(ru_id); + for (uint16_t cc_id = 0; cc_id < 1 /* fh_config->nCC */; cc_id++) { // OAI does not support multiple CC yet. + for(uint32_t ant_id = 0; ant_id < fh_config->neAxc; ant_id++) { + struct xran_prb_map *pRbMap = (struct xran_prb_map *)bufs->dstcp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; + AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMap == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id); + for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) { + oran_sync_info.nRxPkt[cc_id][ant_id][sym_id] = pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt; + pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt = 0; + } + } + } #endif #endif } else @@ -178,7 +207,7 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot #if defined K_RELEASE , uint8_t mu #endif - ) + ) { /* calculate tti and subframe_id from frame, slot num */ int sym_idx = 0; @@ -341,7 +370,6 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) atomic_fetch_sub(&xran_queue_length, 1); oran_sync_info_t *info = NotifiedFifoData(res); -#define MAX_QUEUE_LENGTH_NO_JUMP 3 if (xran_queue_length > 0 && xran_queue_length < MAX_QUEUE_LENGTH_NO_JUMP) { LOG_D(HW, "%4d.%2d TTI processing delay detected\n", info->f, info->sl); } else if (xran_queue_length >= MAX_QUEUE_LENGTH_NO_JUMP) { @@ -440,28 +468,38 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) int start_totalRB = pRbMap->prbMap[0].nRBStart; int32_t local_dst[num_totalRB * N_SC_PER_PRB] __attribute__((aligned(64))); +#if defined K_RELEASE + struct xran_prb_elm *pRbElm = &pRbMap->prbMap[0]; + struct xran_rx_packet_ctl *p_rx_packet_ctl = &pRbMap->sFrontHaulRxPacketCtrl[sym_idx]; + uint32_t one_rb_size = + (((pRbElm->iqWidth == 0) || (pRbElm->iqWidth == 16)) ? (N_SC_PER_PRB * 2 * 2) : (3 * pRbElm->iqWidth + 1)); +#ifndef USE_POLLING + int32_t nRxPkt = info->nRxPkt[cc_id][ant_id][sym_idx]; +#else + int32_t nRxPkt = oran_sync_info.nRxPkt[cc_id][ant_id][sym_idx]; +#endif + LOG_D(HW, "nRxPkt %d\n", nRxPkt); + for (int pkt_idx = 0; pkt_idx < nRxPkt; pkt_idx++) { + uint8_t *pData; + if (fh_init->mtu < p_rx_packet_ctl->nRBSize[pkt_idx] * one_rb_size) + pData = bufs->dst[ant_id % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN] + .pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT] + .pData; + else + pData = p_rx_packet_ctl->pData[pkt_idx]; + int numRB = p_rx_packet_ctl->nRBSize[pkt_idx]; + int startRB = p_rx_packet_ctl->nRBStart[pkt_idx]; + // num_prbu & start_prbu are for UL U-plane only + LOG_D(HW, "p_rx_packet_ctl[%d] startRB[%d]:numRB[%d]\n", pkt_idx, startRB, numRB); + { + { +#elif defined F_RELEASE LOG_D(HW, "[%d.%d] pRbMap->nPrbElm %d\n", *frame, *slot, pRbMap->nPrbElm); for (uint32_t idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) { int numRB, startRB; uint8_t *pData; struct xran_section_desc *p_sec_desc = NULL; struct xran_prb_elm *pRbElm = &pRbMap->prbMap[idxElm]; -#if defined K_RELEASE - 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 < num_totalRB * one_rb_size) - pData = bufs->dst[ant_id % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN] - .pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT] - .pData; - else { - p_sec_desc = &pRbElm->sec_desc[sym_idx]; - pData = p_sec_desc->pData; - } - numRB = num_totalRB; - startRB = start_totalRB; - { - { -#elif defined F_RELEASE // UP_nRBSize & UP_nRBStart are for DL U-plane only LOG_D(HW, "[%d.%d] idxElm[%d] startSym[%d]:numSym[%d] UP_startRB[%d]:UP_numRB[%d] sym_idx[%d] ant_id[%d] pRbElm->nRBStart[%d]:pRbElm->nRBSize[%d]\n", *frame, *slot, idxElm, pRbElm->nStartSymb, pRbElm->numSymb, pRbElm->UP_nRBStart, pRbElm->UP_nRBSize, sym_idx, ant_id, pRbElm->nRBStart, pRbElm->nRBSize); for (int idxDesc = 0; idxDesc < XRAN_MAX_FRAGMENT; idxDesc++) { diff --git a/radio/fhi_72/oaioran.h b/radio/fhi_72/oaioran.h index cf9dfb70cb..0a70e74eee 100644 --- a/radio/fhi_72/oaioran.h +++ b/radio/fhi_72/oaioran.h @@ -14,15 +14,17 @@ typedef struct { uint32_t f; #if defined K_RELEASE uint8_t mu; + // the first column can expand to XRAN_MAX_SECTOR_NR for the support of multiple CCs + int32_t nRxPkt[1][XRAN_MAX_ANTENNA_NR][XRAN_NUM_OF_SYMBOL_PER_SLOT]; #endif } oran_sync_info_t; /** @brief xran callback for fronthaul RX, see xran_5g_fronthault_config(). */ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status #if defined K_RELEASE - , uint8_t mu + , uint8_t mu #endif - ); + ); /** @brief xran callback for time alignment, see xran_reg_physide_cb(). */ int oai_physide_dl_tti_call_back(void *param #if defined K_RELEASE diff --git a/radio/fhi_72/oran-init.c b/radio/fhi_72/oran-init.c index 315347e7d1..0880cac1b3 100644 --- a/radio/fhi_72/oran-init.c +++ b/radio/fhi_72/oran-init.c @@ -94,6 +94,9 @@ static struct xran_prb_map get_xran_prb_map(const struct xran_fh_config *f, cons e->nBeamIndex = 0; e->compMethod = f->ru_conf.compMeth; e->iqWidth = f->ru_conf.iqWidth; +#if defined K_RELEASE + memset(&prbmap.sFrontHaulRxPacketCtrl, 0, XRAN_NUM_OF_SYMBOL_PER_SLOT * sizeof(struct xran_rx_packet_ctl)); +#endif return prbmap; } From 1bc8e64641cfd87c2f8e79894008f9eb830040a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Thu, 26 Mar 2026 11:58:43 +0100 Subject: [PATCH 08/17] Process PRACH packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move PRACH callback in the oaioran.h/c since now used in K release. * Reset the number of PRACH packets. * Handle PRACH queue in the same manner as for PUSCH (95c8fa46). Co-authored-by: Romain Beurdouche Signed-off-by: Teodora Vladić --- radio/fhi_72/README.md | 12 +- radio/fhi_72/oaioran.c | 231 ++++++++++++++++++++++++++++++++---- radio/fhi_72/oaioran.h | 6 + radio/fhi_72/oran-init.c | 75 +++++++++--- radio/fhi_72/oran-init.h | 2 +- radio/fhi_72/oran_isolate.c | 20 +++- 6 files changed, 301 insertions(+), 45 deletions(-) diff --git a/radio/fhi_72/README.md b/radio/fhi_72/README.md index e0585d22dc..48e21220fb 100644 --- a/radio/fhi_72/README.md +++ b/radio/fhi_72/README.md @@ -28,7 +28,8 @@ It calls various helper function in the same file to set up DPDK memory buffer - `oai_xran_fh_rx_prach_callback()` through `xran_5g_prach_req()`: callback for PRACH data; not currently used and implemented in PUSCH data callback. - `oai_physide_dl_tti_call_back()` through `xran_reg_physide_cb()`: only used - to unblock timing in `oai_xran_fh_rx_callback()` upon first xran call. + to unblock timing in `oai_xran_fh_rx_callback()` and `oai_xran_fh_rx_prach_callback()` + upon first xran call. More detailed information about the xran callbacks can be taken from the xran documentation. @@ -40,9 +41,10 @@ PDSCH. For PDSCH, `oran_fh_if4p5_south_out()` calls `xran_fh_tx_send_slot()` that optionally compresses IQ data, then writes it into IQ buffers of xran. -For PUSCH/PRACH, `oran_fh_if4p5_south_in()` calls `xran_fh_rx_read_slot()` that -blocks and waits for the next slot. This is done through either a message -queue, or through polling, which in both cases depends on xran calling the -callback `oai_xran_fh_rx_callback()` as installed during xran initialization. +For PUSCH/PRACH, `oran_fh_if4p5_south_in()` calls `xran_fh_rx_read_slot()`/ +`xran_fh_rx_prach_read_slot()` that blocks and waits for the next slot. +This is done through either a message queue, or through polling, which in both +cases depends on xran calling the callbacks `oai_xran_fh_rx_callback()`/ +`oai_xran_fh_rx_prach_callback()` as installed during xran initialization. Once unblocked, it reads first PRACH data, then PUSCH data, before returning to OAI. diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 4284912c3d..f340b08dd1 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -46,8 +46,16 @@ int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id extern notifiedFIFO_t oran_sync_fifo; #define MAX_QUEUE_LENGTH_NO_JUMP 3 atomic_int xran_queue_length = 0; +atomic_int xran_queue_prach_length = 0; +#if defined K_RELEASE +extern notifiedFIFO_t oran_sync_fifo_prach; +#endif #else volatile oran_sync_info_t oran_sync_info = {0}; +#if defined K_RELEASE +volatile oran_sync_info_t oran_sync_info_prach = {0}; +volatile bool prach_rx_awaiting = false; +#endif #endif /** @details xran-specific callback, called when all packets for given CC and @@ -184,8 +192,109 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status } // rx_sym == 7 } -/** @details Only used to unblock timing in oai_xran_fh_rx_callback() on first - * call. */ +void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status +#if defined K_RELEASE + , uint8_t mu +#endif + ) +{ +#if defined K_RELEASE + struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag; + + static int32_t last_slot = -1; + // static int32_t last_frame = -1; + + const struct xran_fh_init *fh_init = get_xran_fh_init(); + int num_ports = fh_init->xran_ports; + + const int slots_in_sf = 1 << mu; + const int sf_in_frame = 10; + + static int rx_RU[XRAN_PORTS_NUM][160] = {0}; + uint32_t tti = callback_tag->slotiId; + uint32_t frame = XranGetFrameNum(tti, 0, sf_in_frame, slots_in_sf); + uint32_t subframe = XranGetSubFrameNum(tti, slots_in_sf, sf_in_frame); + uint32_t slot = XranGetSlotNum(tti, slots_in_sf); + + uint32_t rx_sym = callback_tag->symbol & 0xFF; + uint32_t ru_id = callback_tag->oXuId; + + LOG_D(HW, "prach_rx_callback at %4d.%3d (subframe %d), rx_sym %d ru_id %d\n", frame, slot, subframe, rx_sym, ru_id); + + if (rx_sym == 7) { // in F release this value is defined as XRAN_FULL_CB_SYM (full slot (offset + 7)) + // if xran did not call xran_physide_dl_tti callback, it's not ready yet. + // wait till first callback to advance counters, because otherwise users + // would see periodic output with only "0" in stats counters + if (!first_call_set) + return; + uint32_t slot2 = slot + (subframe * slots_in_sf); + 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(HW, "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_prach, NULL); + oran_sync_info_t *info = NotifiedFifoData(req); + info->tti = tti; + info->sl = slot2; + info->f = frame; + info->mu = mu; +#else + LOG_D(HW, "Writing PRACH slot %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); + oran_sync_info_prach.tti = tti; + oran_sync_info_prach.sl = slot2; + oran_sync_info_prach.f = frame; + oran_sync_info_prach.mu = mu; +#endif + struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag; + uint32_t tti = callback_tag->slotiId; + uint32_t ru_id = callback_tag->oXuId; + for (int ru_idx = 0; ru_idx < num_ports; ru_idx++) { + oran_buf_list_t *bufs = get_xran_buffers(ru_idx); + struct xran_fh_config *fh_config = get_xran_fh_config(ru_idx); + for (uint16_t cc_id = 0; cc_id < 1 /* fh_config->nCC */; cc_id++) { // OAI does not support multiple CC yet. + for(uint32_t ant_id = 0; ant_id < fh_config->neAxc; ant_id++) { + struct xran_prb_map *pRbMap = (struct xran_prb_map *)bufs->prachdstdecomp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; + AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMapPrach == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id); + for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) { + AssertFatal(pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt <= 1, "PRACH segmentation is not supported\n"); +#ifndef USE_POLLING + info->nRxPkt[cc_id][ant_id][sym_id] = pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt; +#else + oran_sync_info_prach.nRxPkt[cc_id][ant_id][sym_id] = pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt; +#endif + pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt = 0; + } + } + } + } +#ifndef USE_POLLING + LOG_D(HW, "Push PRACH slot %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); + atomic_fetch_add(&xran_queue_prach_length, 1); + pushNotifiedFIFO(&oran_sync_fifo_prach, req); +#else + prach_rx_awaiting = true; +#endif + } else + LOG_E(HW, "Cannot Push PRACH slot %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; + } // rx_sym == 7 +#elif defined F_RELEASE + rte_pause(); +#endif +} + +/** @details Only used to unblock timing in oai_xran_fh_rx_callback()/oai_xran_fh_rx_prach_callback() + * on first call. */ int oai_physide_dl_tti_call_back(void *param #if defined K_RELEASE , uint8_t mu @@ -198,17 +307,67 @@ int oai_physide_dl_tti_call_back(void *param return 0; } -/** @brief Reads PRACH data from xran buffers. +/** @details Read PRACH data from xran buffers. + * If I/Q compression (bitwidth < 16 bits) is configured, decompresses the data + * before writing. * - * @details Reads PRACH data from xran-specific buffers and, if I/Q compression - * (bitwidth < 16 bits) is configured, uncompresses the data. Places PRACH data - * in OAI buffer. */ -static int read_prach_data(ru_info_t *ru, int frame, int slot -#if defined K_RELEASE - , uint8_t mu -#endif - ) + * Function is blocking and waits for next frame/slot combination. It is unblocked + * by oai_xran_fh_rx_prach_callback(). If K_RELEASE, it writes the current slot into parameters + * frame/slot. If F_RELEASE, it takes the frame/slot. */ +int xran_fh_rx_prach_read_slot(prach_list_t *prach_list, ru_info_t *ru, int *frame, int *slot) { +#if defined K_RELEASE +#ifndef USE_POLLING + // pull next even from oran_sync_fifo_prach if any + notifiedFIFO_elt_t *res = pullNotifiedFIFO(&oran_sync_fifo_prach); + atomic_fetch_sub(&xran_queue_prach_length, 1); + oran_sync_info_t *info = NotifiedFifoData(res); + + if (xran_queue_prach_length > 0 && xran_queue_prach_length < MAX_QUEUE_LENGTH_NO_JUMP) { + LOG_D(HW, "%4d.%2d TTI processing delay detected\n", info->f, info->sl); + } else if (xran_queue_prach_length >= MAX_QUEUE_LENGTH_NO_JUMP) { + uint32_t old_f = info->f; + uint32_t old_sl = info->sl; + // set the frame/slot info to what is in the last message + notifiedFIFO_elt_t *f; + while ((f = pollNotifiedFIFO(&oran_sync_fifo_prach)) != NULL) { + atomic_fetch_sub(&xran_queue_prach_length, 1); + delNotifiedFIFO_elt(res); + res = f; + } + info = NotifiedFifoData(res); + LOG_W(HW, "PRACH TTI processing delay detected, skipping %4d.%2d => %4d.%2d\n", old_f, old_sl, info->f, info->sl); + DevAssert(xran_queue_prach_length == 0); + } + + int slot = info->sl; + int frame = info->f; + uint8_t mu = info->mu; + delNotifiedFIFO_elt(res); +#else +#error "POLLING is not supported for K release unless you know how to fix the race condition on prach_rx_awaiting" + if (!prach_rx_awaiting) { + return (0); + } else { + prach_rx_awaiting = false; + } + int slot = oran_sync_info_prach.sl; + int frame = oran_sync_info_prach.f; + uint8_t mu = oran_sync_info_prach.mu; + uint32_t tti_in = oran_sync_info_prach.tti; + + static int last_slot = -1; + LOG_D(HW, "oran slot %d, last_slot %d\n", *slot, last_slot); + int cnt = 0; + // while (*slot == last_slot) { + while (tti_in == oran_sync_info_prach.tti) { + //*slot = oran_sync_info.sl; + cnt++; + } + LOG_D(HW, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot); + last_slot = *slot; +#endif +#endif /* calculate tti and subframe_id from frame, slot num */ int sym_idx = 0; @@ -235,19 +394,49 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot #elif defined F_RELEASE int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology; #endif + int tti = slots_per_frame * (frame) + (slot); int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports; + /* If it is PRACH slot, copy prach IQ from XRAN PRACH buffer to OAI PRACH buffer */ if (ru->prach_buf) { - for (sym_idx = prach_start_sym; sym_idx < prach_end_sym; sym_idx++) { - for (int aa = 0; aa < ru->nb_rx; aa++) { + for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet. + for (int aa = 0; aa < ru->nb_rx; aa++) { + for (sym_idx = prach_start_sym; sym_idx < prach_end_sym; sym_idx++) { int16_t *dst, *src; int idx = 0; oran_buf_list_t *bufs = get_xran_buffers(aa / nb_rx_per_ru); // hardcoded to use only first prach occasion dst = (int16_t *)ru->prach_buf[aa][0]; +#if defined K_RELEASE + struct xran_prb_map * pPrbMap = (struct xran_prb_map *)bufs->prachdstdecomp[aa % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; + struct xran_rx_packet_ctl *p_rx_packet_ctl = &pPrbMap->sFrontHaulRxPacketCtrl[sym_idx]; +#ifndef USE_POLLING + int32_t nRxPkt = info->nRxPkt[cc_id][aa][sym_idx]; +#else + int32_t nRxPkt = oran_sync_info.nRxPkt[cc_id][aa][sym_idx]; +#endif + if (nRxPkt == 0) { + LOG_E(HW, "read_prach %d.%d.%d saa = %d: nRxPkt = 0!\n", *frame, *slot, sym_idx, aa); + memset(&dst[sym_idx], 0, N_ZC * 2 * sizeof(*dst)); + continue; + } else if (nRxPkt > 1) { // protection + LOG_E(HW, "read_prach %d.%d.%d saa = %d: nRxPkt = %d!\n", *frame, *slot, sym_idx, aa, nRxPkt); + memset(&dst[sym_idx], 0, N_ZC * 2 * sizeof(*dst)); + continue; + } else { + src = (int16_t *)p_rx_packet_ctl->pData[0]; + if (src == NULL) { // protection + LOG_E(HW, "read_prach %d.%d.%d saa = %d: src = NULL!!\n", *frame, *slot, sym_idx, aa); + memset(&dst[sym_idx], 0, N_ZC * 2 * sizeof(*dst)); + continue; + } + } + num_prbu = p_rx_packet_ctl->nRBSize[0]; +#elif defined F_RELEASE src = (int16_t *)bufs->prachdstdecomp[aa % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers[sym_idx].pData; +#endif /* convert Network order to host order */ if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) { if (sym_idx == prach_start_sym) { @@ -289,9 +478,11 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot for (idx = 0; idx < (N_ZC * 2); idx++) dst[idx] += (local_dst[idx + g_kbar]); } // COMPMETHOD_BLKFLOAT - } // aa - } // symb_indx + } // sym_idx + } // aa + } // cc_id } // ru->prach_buf + return (0); } @@ -347,8 +538,8 @@ static bool is_tdd_ul_guard_slot(const struct xran_frame_config *frame_conf, int return is_tdd_ul_symbol(frame_conf, slot, XRAN_NUM_OF_SYMBOL_PER_SLOT - 1); } -/** @details Read PRACH and PUSCH data from xran buffers. If - * I/Q compression (bitwidth < 16 bits) is configured, deccompresses the data +/** @details Read PUSCH data from xran buffers. + * If I/Q compression (bitwidth < 16 bits) is configured, decompresses the data * before writing. Prints ON TIME counters every 128 frames. * * Function is blocking and waits for next frame/slot combination. It is unblocked @@ -423,9 +614,9 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) int tti = slots_per_frame * (*frame) + (*slot); - read_prach_data(ru, *frame, *slot -#if defined K_RELEASE - , mu + read_prach_data(ru +#if defined F_RELEASE + , *frame, *slot #endif ); diff --git a/radio/fhi_72/oaioran.h b/radio/fhi_72/oaioran.h index 0a70e74eee..324fd55283 100644 --- a/radio/fhi_72/oaioran.h +++ b/radio/fhi_72/oaioran.h @@ -21,6 +21,12 @@ typedef struct { /** @brief xran callback for fronthaul RX, see xran_5g_fronthault_config(). */ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status +#if defined K_RELEASE + , uint8_t mu +#endif + ); +/** @brief xran callback for fronthaul PRACH RX, see xran_5g_prach_req(). */ +void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status #if defined K_RELEASE , uint8_t mu #endif diff --git a/radio/fhi_72/oran-init.c b/radio/fhi_72/oran-init.c index 0880cac1b3..c5acd26c71 100644 --- a/radio/fhi_72/oran-init.c +++ b/radio/fhi_72/oran-init.c @@ -100,6 +100,31 @@ static struct xran_prb_map get_xran_prb_map(const struct xran_fh_config *f, cons return prbmap; } +#if defined K_RELEASE +static struct xran_prb_map get_xran_prb_map_prach(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, + .nPrbElm = 1, + }; + struct xran_prb_elm *e = &prbmap.prbMap[0]; + e->nStartSymb = 0; + e->numSymb = 14; + e->nRBStart = 0; + e->nRBSize = 12; + e->nBeamIndex = 0; + e->compMethod = f->ru_conf.compMeth; + e->iqWidth = f->ru_conf.iqWidth; + memset(&prbmap.sFrontHaulRxPacketCtrl, 0, XRAN_NUM_OF_SYMBOL_PER_SLOT * sizeof(struct xran_rx_packet_ctl)); + return prbmap; +} +#endif + static uint32_t next_power_2(uint32_t num) { uint32_t power = 2; @@ -244,16 +269,6 @@ static void oran_allocate_cplane_buffers(void *instHandle, printf("xran_bm_allocate_buffer() hInstance %p poolIdx %u count %u\n", instHandle, poolPrb, count1); } -/* callback not actively used */ -static void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status -#if defined K_RELEASE - , uint8_t mu -#endif - ) -{ - rte_pause(); -} - static void oran_allocate_buffers(void *handle, int xran_inst, int num_sectors, @@ -287,6 +302,9 @@ static void oran_allocate_buffers(void *handle, // DL/UL PRB mapping depending on the duplex mode struct xran_prb_map dlPm = get_xran_prb_map(fh_config, XRAN_DIR_DL, 0, 14); struct xran_prb_map ulPm = get_xran_prb_map(fh_config, XRAN_DIR_UL, 0, 14); +#if defined K_RELEASE + struct xran_prb_map prachPm = get_xran_prb_map_prach(fh_config); +#endif struct xran_prb_map dlPmMixed = {0}; struct xran_prb_map ulPmMixed = {0}; uint32_t idx = 0; @@ -314,6 +332,17 @@ static void oran_allocate_buffers(void *handle, uint32_t numPrbElm = (fh_config->RunSlotPrbMapBySymbolEnable) ? XRAN_NUM_OF_SYMBOL_PER_SLOT : xran_get_num_prb_elm(&dlPm, mtu); uint32_t size_of_prb_map = sizeof(struct xran_prb_map) + sizeof(struct xran_prb_elm) * (numPrbElm); +#if defined K_RELEASE + oran_cplane_prb_config prachConf = { + .nTddPeriod = fh_config->frame_conf.nTddPeriod, + .mixed_slot_index = idx, + .slotMap = prachPm, + .mixedSlotMap = prachPm, + }; + + uint32_t numPrbElmPrach = (fh_config->RunSlotPrbMapBySymbolEnable) ? XRAN_NUM_OF_SYMBOL_PER_SLOT : xran_get_num_prb_elm(&prachPm, mtu); + uint32_t size_of_prb_map_prach = sizeof(struct xran_prb_map) + sizeof(struct xran_prb_elm) * (numPrbElmPrach); +#endif // PDSCH #if defined K_RELEASE @@ -352,41 +381,53 @@ static void oran_allocate_buffers(void *handle, // 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); +#if defined K_RELEASE + oran_allocate_cplane_buffers(pi->instanceHandle, + bl->prachdstdecomp, + bl->bufs.prachdecomp, + xran_max_antenna_nr, + xran_max_sections_per_slot, + mtu, + fh_config, + size_of_prb_map_prach, + &prachConf); +#elif defined F_RELEASE // 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]; + bl->prachdstdecomp[a][j].pBuffers = &bl->bufs.prachdecomp[a][j]; 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; } } } +#endif 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]; + 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]; 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]; + prachdst[a][j] = &bl->prachdst[a][j]; + prachdstdecomp[a][j] = &bl->prachdstdecomp[a][j]; } } #if defined K_RELEASE xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->pusch_tag, fh_config->nNumerology[0]); - xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag, fh_config->nNumerology[0]); + xran_5g_prach_req(pi->instanceHandle, prachdst, prachdstdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag, fh_config->nNumerology[0]); #elif defined F_RELEASE xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->pusch_tag); - xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag); + xran_5g_prach_req(pi->instanceHandle, prachdst, prachdstdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag); #endif } diff --git a/radio/fhi_72/oran-init.h b/radio/fhi_72/oran-init.h index 135e2cf307..d1d4d43ee9 100644 --- a/radio/fhi_72/oran-init.h +++ b/radio/fhi_72/oran-init.h @@ -15,7 +15,7 @@ typedef struct oran_bufs { 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]; + struct xran_flat_buffer prachdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN]; } oran_bufs_t; typedef struct oran_buf_list { diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index fd6ba98232..b2eb9f576d 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -39,6 +39,9 @@ typedef struct { } oran_eth_state_t; notifiedFIFO_t oran_sync_fifo; +#if defined K_RELEASE +notifiedFIFO_t oran_sync_fifo_prach; +#endif int trx_oran_start(openair0_device_t *device) { @@ -279,12 +282,22 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) fsn_t now = {.f = *frame, .s = *slot, .mu = gNB->frame_parms.numerology_index}; if (get_next_nr_prach(&gNB->prach_ru_queue, &now, &p)) { struct xran_fh_config *fh_cfg = get_xran_fh_config(0); - int slots_per_subframe = 1 << fh_cfg->frame_conf.nNumerology; +#if defined F_RELEASE + uint8_t mu = fh_cfg->frame_conf.nNumerology; +#elif defined K_RELEASE + uint8_t mu = fh_cfg->nNumerology[0]; +#endif + int slots_per_subframe = 1 << mu; uint32_t subframe = *slot / slots_per_subframe; // `slot` = slot in which PRACH is received // PRACH occasion in a frame if and only if SFN % x == y, TS 38.211 Table 6.3.3.2-2/3/4 nr_prach_info_t prach_info = get_prach_info(0); bool is_prach_frame = (*frame % prach_info.x == prach_info.y); - bool is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (p.slot % slots_per_subframe)); // `p.slot` = slot in which PRACH is scheduled + bool is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (p.slot % slots_per_subframe) +#if defined K_RELEASE + , mu +#endif + ); // `p.slot` = slot in which PRACH is scheduled + bool is_prach_slot = is_prach_frame && check_xran_prach_slot; if (is_prach_slot) { ru_info.prach_buf = p.prach_buf; } else { @@ -458,6 +471,9 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device_t // create message queues for ORAN sync initNotifiedFIFO(&oran_sync_fifo); +#if defined K_RELEASE + initNotifiedFIFO(&oran_sync_fifo_prach); +#endif eth->e.flags = ETH_RAW_IF4p5_MODE; eth->e.compression = NO_COMPRESS; From d06bd3d49f35cfaf79c7f294b2e40d44db66af2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Tue, 24 Mar 2026 15:20:42 +0100 Subject: [PATCH 09/17] Separate PRACH and PUSCH packet processing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * rename read_prach_data() to xran_rx_prach_read_slot() * in F release, there is no PRACH queue so `frame` and `slot` are passed as input; in K release, `frame` and `slot` are taken from the PRACH queue Note: since the PUSCH callback is the called before PRACH callback, this commit is correct but the timing for PRACH processing is just a little bit late. In previous state, PRACH processing was done inside the function of PUSCH processing. => next commit will just reverse the order. Signed-off-by: Teodora Vladić --- radio/fhi_72/oaioran.c | 58 +++++++++++++++++++++++++++---------- radio/fhi_72/oran_isolate.c | 50 +++++++++----------------------- radio/fhi_72/oran_isolate.h | 10 ++++++- 3 files changed, 65 insertions(+), 53 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index f340b08dd1..74c56ae36e 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -25,6 +25,7 @@ #include "oran-config.h" // for g_kbar #include "common/utils/threadPool/notified_fifo.h" +#include "common/utils/fsn.h" #define N_SC_PER_PRB 12 @@ -314,7 +315,7 @@ int oai_physide_dl_tti_call_back(void *param * Function is blocking and waits for next frame/slot combination. It is unblocked * by oai_xran_fh_rx_prach_callback(). If K_RELEASE, it writes the current slot into parameters * frame/slot. If F_RELEASE, it takes the frame/slot. */ -int xran_fh_rx_prach_read_slot(prach_list_t *prach_list, ru_info_t *ru, int *frame, int *slot) +int xran_fh_rx_prach_read_slot(PHY_VARS_gNB *gNB, ru_info_t *ru, int *frame, int *slot) { #if defined K_RELEASE #ifndef USE_POLLING @@ -340,8 +341,8 @@ int xran_fh_rx_prach_read_slot(prach_list_t *prach_list, ru_info_t *ru, int *fra DevAssert(xran_queue_prach_length == 0); } - int slot = info->sl; - int frame = info->f; + *slot = info->sl; + *frame = info->f; uint8_t mu = info->mu; delNotifiedFIFO_elt(res); #else @@ -351,8 +352,8 @@ int xran_fh_rx_prach_read_slot(prach_list_t *prach_list, ru_info_t *ru, int *fra } else { prach_rx_awaiting = false; } - int slot = oran_sync_info_prach.sl; - int frame = oran_sync_info_prach.f; + *slot = oran_sync_info_prach.sl; + *frame = oran_sync_info_prach.f; uint8_t mu = oran_sync_info_prach.mu; uint32_t tti_in = oran_sync_info_prach.tti; @@ -368,6 +369,35 @@ int xran_fh_rx_prach_read_slot(prach_list_t *prach_list, ru_info_t *ru, int *fra last_slot = *slot; #endif #endif + + prach_item_t p; + fsn_t now = {.f = *frame, .s = *slot, .mu = gNB->frame_parms.numerology_index}; + if (get_next_nr_prach(&gNB->prach_ru_queue, &now, &p)) { + struct xran_fh_config *fh_cfg = get_xran_fh_config(0); +#if defined F_RELEASE + uint8_t mu = fh_cfg->frame_conf.nNumerology; +#elif defined K_RELEASE + uint8_t mu = fh_cfg->nNumerology[0]; +#endif + int slots_per_subframe = 1 << mu; + uint32_t subframe = *slot / slots_per_subframe; // `slot` = slot in which PRACH is received + // PRACH occasion in a frame if and only if SFN % x == y, TS 38.211 Table 6.3.3.2-2/3/4 + nr_prach_info_t prach_info = get_prach_info(0); + bool is_prach_frame = (*frame % prach_info.x == prach_info.y); + bool is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (p.slot % slots_per_subframe) +#if defined K_RELEASE + , mu +#endif + ); // `p.slot` = slot in which PRACH is scheduled + if (is_prach_slot) { + ru->prach_buf = p.prach_buf; + } else { + LOG_W(HW, "[%d.%d] Expected PRACH reception of scheduled slot %d\n", *frame, *slot, p.slot); + } + } else { + return (0); + } + /* calculate tti and subframe_id from frame, slot num */ int sym_idx = 0; @@ -395,12 +425,10 @@ int xran_fh_rx_prach_read_slot(prach_list_t *prach_list, ru_info_t *ru, int *fra int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology; #endif - int tti = slots_per_frame * (frame) + (slot); + int tti = slots_per_frame * (*frame) + (*slot); int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports; - /* If it is PRACH slot, copy prach IQ from XRAN PRACH buffer to OAI PRACH buffer */ - if (ru->prach_buf) { for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet. for (int aa = 0; aa < ru->nb_rx; aa++) { for (sym_idx = prach_start_sym; sym_idx < prach_end_sym; sym_idx++) { @@ -481,7 +509,13 @@ int xran_fh_rx_prach_read_slot(prach_list_t *prach_list, ru_info_t *ru, int *fra } // sym_idx } // aa } // cc_id - } // ru->prach_buf + + // after reading PRACH, write back to queue + bool success = spsc_q_put(&gNB->prach_l1rx_queue, &p, sizeof(p)); + // assume prach_l1rx_queue never full: prach_ru_queue filled at + // constant pace, but prach_l1rx_queue emptied as fast as possible, + // see rx_func() + DevAssert(success); return (0); } @@ -614,12 +648,6 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) int tti = slots_per_frame * (*frame) + (*slot); - read_prach_data(ru -#if defined F_RELEASE - , *frame, *slot -#endif - ); - const struct xran_fh_init *fh_init = get_xran_fh_init(); #if defined K_RELEASE int fftsize = 1 << fh_cfg->perMu[mu].nULFftSize; diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index b2eb9f576d..29da80a979 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -12,9 +12,7 @@ #include "xran_sync_api.h" #include "common/utils/LOG/log.h" -#include "common/utils/fsn.h" #include "openair1/PHY/defs_gNB.h" -#include "openair1/PHY/NR_TRANSPORT/nr_transport_proto.h" #include "oaioran.h" #include "oran-config.h" @@ -268,6 +266,8 @@ int trx_oran_ctlrecv(openair0_device_t *device, void *msg, ssize_t msg_len) void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) { + int ret = 0; // return code for PUSCH/PRACH processing + ru_info_t ru_info = { .nb_rx = ru->nb_rx * ru->num_beams_period, .nb_tx = ru->nb_tx * ru->num_beams_period, @@ -277,54 +277,30 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) .prach_buf = NULL, }; - prach_item_t p; - PHY_VARS_gNB *gNB = ru->gNB_list[0]; - fsn_t now = {.f = *frame, .s = *slot, .mu = gNB->frame_parms.numerology_index}; - if (get_next_nr_prach(&gNB->prach_ru_queue, &now, &p)) { - struct xran_fh_config *fh_cfg = get_xran_fh_config(0); + /* Firstly, process PRACH packets */ + int f_prach, sl_prach; #if defined F_RELEASE - uint8_t mu = fh_cfg->frame_conf.nNumerology; -#elif defined K_RELEASE - uint8_t mu = fh_cfg->nNumerology[0]; + // no PRACH callback (no queue) in F release so use the expected combination + f_prach = *frame; + sl_prach = *slot; #endif - int slots_per_subframe = 1 << mu; - uint32_t subframe = *slot / slots_per_subframe; // `slot` = slot in which PRACH is received - // PRACH occasion in a frame if and only if SFN % x == y, TS 38.211 Table 6.3.3.2-2/3/4 - nr_prach_info_t prach_info = get_prach_info(0); - bool is_prach_frame = (*frame % prach_info.x == prach_info.y); - bool is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (p.slot % slots_per_subframe) -#if defined K_RELEASE - , mu -#endif - ); // `p.slot` = slot in which PRACH is scheduled - bool is_prach_slot = is_prach_frame && check_xran_prach_slot; - if (is_prach_slot) { - ru_info.prach_buf = p.prach_buf; - } else { - LOG_W(HW, "[%d.%d] Expected PRACH reception of scheduled slot %d\n", *frame, *slot, p.slot); - } + ret = xran_fh_rx_prach_read_slot(ru->gNB_list[0], &ru_info, &f_prach, &sl_prach); + if (ret != 0) { + printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX PRACH function \n", f_prach, sl_prach); } - RU_proc_t *proc = &ru->proc; + /* Secondly, process PUSCH packets */ + RU_proc_t *proc = &ru->proc; // to check if (frame,slot) combination corresponds to the expected PUSCH one int f, sl; LOG_D(HW, "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); + ret = xran_fh_rx_read_slot(&ru_info, &f, &sl); stop_meas(&ru->rx_fhaul); LOG_D(HW, "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); } - if (ru_info.prach_buf) { - // xran_fh_rx_read_slot() should have read PRACH, write back to queue - bool success = spsc_q_put(&gNB->prach_l1rx_queue, &p, sizeof(p)); - // assume prach_l1rx_queue never full: prach_ru_queue filled at - // constant pace, but prach_l1rx_queue emptied as fast as possible, - // see rx_func() - DevAssert(success); - } - int slots_per_frame = 10 << (ru->openair0_cfg.nr_scs_for_raster); proc->tti_rx = sl; proc->frame_rx = f; diff --git a/radio/fhi_72/oran_isolate.h b/radio/fhi_72/oran_isolate.h index afdf443596..450115fcff 100644 --- a/radio/fhi_72/oran_isolate.h +++ b/radio/fhi_72/oran_isolate.h @@ -14,6 +14,8 @@ #include "openair1/PHY/impl_defs_nr.h" #include "openair1/PHY/TOOLS/tools_defs.h" #include "openair1/PHY/defs_nr_common.h" +#include "openair1/PHY/NR_TRANSPORT/nr_transport_proto.h" + /* * Structure added to bear the information needed from OAI RU */ @@ -38,12 +40,18 @@ typedef struct ru_info_s { c16_t (*prach_buf)[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX][NR_PRACH_SEQ_LEN_L]; } ru_info_t; -/** @brief Reads RX data (PRACH/PUSCH) of next slot. +/** @brief Reads RX data PUSCH of next slot. * * @param ru pointer to structure keeping pointers to OAI data. * @param frame output of the frame which has been read. * @param slot output of the slot which has been read. */ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot); +/** @brief Reads RX data PRACH of next slot. + * + * @param ru pointer to structure keeping pointers to OAI data. + * @param frame input for F_RELEASE, output for K_RELEASE. + * @param slot input for F_RELEASE, output for K_RELEASE. */ +int xran_fh_rx_prach_read_slot(PHY_VARS_gNB *gNB, ru_info_t *ru, int *frame, int *slot); /** @brief Writes TX data (PDSCH) of given slot. */ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp); From 84a1eb8b07efbb3623f64db2e1410ef41dbcdd81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Wed, 25 Mar 2026 22:18:38 +0100 Subject: [PATCH 10/17] Reverse the Rx processing order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First process PUSCH and then PRACH because the PUSCH callback is called before PRACH callback. Signed-off-by: Teodora Vladić --- radio/fhi_72/README.md | 2 +- radio/fhi_72/oran_isolate.c | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/radio/fhi_72/README.md b/radio/fhi_72/README.md index 48e21220fb..e161ceaf40 100644 --- a/radio/fhi_72/README.md +++ b/radio/fhi_72/README.md @@ -46,5 +46,5 @@ For PUSCH/PRACH, `oran_fh_if4p5_south_in()` calls `xran_fh_rx_read_slot()`/ This is done through either a message queue, or through polling, which in both cases depends on xran calling the callbacks `oai_xran_fh_rx_callback()`/ `oai_xran_fh_rx_prach_callback()` as installed during xran initialization. -Once unblocked, it reads first PRACH data, then PUSCH data, before returning to +Once unblocked, it reads first PUSCH data, then PRACH data, before returning to OAI. diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 29da80a979..4f45a6cf18 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -277,19 +277,7 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) .prach_buf = NULL, }; - /* Firstly, process PRACH packets */ - int f_prach, sl_prach; -#if defined F_RELEASE - // no PRACH callback (no queue) in F release so use the expected combination - f_prach = *frame; - sl_prach = *slot; -#endif - ret = xran_fh_rx_prach_read_slot(ru->gNB_list[0], &ru_info, &f_prach, &sl_prach); - if (ret != 0) { - printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX PRACH function \n", f_prach, sl_prach); - } - - /* Secondly, process PUSCH packets */ + /* Firstly, process PUSCH packets */ RU_proc_t *proc = &ru->proc; // to check if (frame,slot) combination corresponds to the expected PUSCH one int f, sl; LOG_D(HW, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]); @@ -301,6 +289,18 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX function \n", f, sl); } + /* Secondly, process PRACH packets */ + int f_prach, sl_prach; +#if defined F_RELEASE + // no PRACH callback (no queue) in F release so use the expected combination + f_prach = *frame; + sl_prach = *slot; +#endif + ret = xran_fh_rx_prach_read_slot(ru->gNB_list[0], &ru_info, &f_prach, &sl_prach); + if (ret != 0) { + printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX PRACH function \n", f_prach, sl_prach); + } + int slots_per_frame = 10 << (ru->openair0_cfg.nr_scs_for_raster); proc->tti_rx = sl; proc->frame_rx = f; From b92936f7d7a397b9d0665f72f60391120f8a33e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Thu, 26 Mar 2026 13:38:45 +0100 Subject: [PATCH 11/17] Move the Tx/Rx counters logging in one function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Teodora Vladić --- radio/fhi_72/oaioran.c | 103 +++++++++++++++++++----------------- radio/fhi_72/oran_isolate.c | 1 + radio/fhi_72/oran_isolate.h | 2 + 3 files changed, 58 insertions(+), 48 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 74c56ae36e..94bb5dd259 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -59,6 +59,60 @@ volatile bool prach_rx_awaiting = false; #endif #endif +/* Prints TX_TOTAL, RX_TOTAL, RX_ON_TIME, RX_ERR_DROP counters every 128 frames. */ +void print_fhi_counters(ru_info_t *ru, const int frame, const int slot) +{ + 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]; + + const struct xran_fh_init *fh_init = get_xran_fh_init(); + for (int o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { +#if defined F_RELEASE + if ((frame & 0x7f) == 0 && slot == 0 && xran_get_common_counters(gxran_handle, &x_counters[0]) == XRAN_STATUS_SUCCESS) { +#elif defined K_RELEASE + if ((frame & 0x7f) == 0 && slot == 0 && xran_get_common_counters(gxran_handle[o_xu_id], &x_counters[o_xu_id]) == XRAN_STATUS_SUCCESS) { +#endif + LOG_I(HW, + "[%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(HW, + "[%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 defined K_RELEASE + LOG_I(HW, + "[%s%d][drop errors %7d ecpri errors %7d cp errors %7d up errors %7d pusch errors %7d prach errors %7d]\n", + "o_du", + o_xu_id, + x_counters[o_xu_id].rx_err_drop, + x_counters[o_xu_id].rx_err_ecpri, + x_counters[o_xu_id].rx_err_cp, + x_counters[o_xu_id].rx_err_up, + x_counters[o_xu_id].rx_err_pusch, + x_counters[o_xu_id].rx_err_prach); +#endif + 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; + } + } +} + /** @details xran-specific callback, called when all packets for given CC and * 1/4, 1/2, 3/4, all symbols of a slot arrived. Currently, only used to get * timing information and unblock another thread in xran_fh_rx_read_slot() @@ -574,7 +628,7 @@ static bool is_tdd_ul_guard_slot(const struct xran_frame_config *frame_conf, int /** @details Read PUSCH data from xran buffers. * If I/Q compression (bitwidth < 16 bits) is configured, decompresses the data - * before writing. Prints ON TIME counters every 128 frames. + * before writing. * * Function is blocking and waits for next frame/slot combination. It is unblocked * by oai_xran_fh_rx_callback(). It writes the current slot into parameters @@ -585,9 +639,6 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) int32_t *pos = NULL; int idx = 0; - 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 event from oran_sync_fifo @@ -792,50 +843,6 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) } // sym_ind } // ant_ind } // vv_inf - for (int o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { -#if defined F_RELEASE - if ((*frame & 0x7f) == 0 && *slot == 0 && xran_get_common_counters(gxran_handle, &x_counters[0]) == XRAN_STATUS_SUCCESS) { -#elif defined K_RELEASE - if ((*frame & 0x7f) == 0 && *slot == 0 && xran_get_common_counters(gxran_handle[o_xu_id], &x_counters[o_xu_id]) == XRAN_STATUS_SUCCESS) { -#endif - LOG_I(HW, - "[%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(HW, - "[%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 defined K_RELEASE - LOG_I(HW, - "[%s%d][drop errors %7d ecpri errors %7d cp errors %7d up errors %7d pusch errors %7d prach errors %7d]\n", - "o_du", - o_xu_id, - x_counters[o_xu_id].rx_err_drop, - x_counters[o_xu_id].rx_err_ecpri, - x_counters[o_xu_id].rx_err_cp, - x_counters[o_xu_id].rx_err_up, - x_counters[o_xu_id].rx_err_pusch, - x_counters[o_xu_id].rx_err_prach); -#endif - 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); } diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 4f45a6cf18..5d3a624555 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -308,6 +308,7 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) proc->frame_tx = (sl > (slots_per_frame - 1 - ru->sl_ahead)) ? (f + 1) & 1023 : f; if (proc->first_rx == 0) { + print_fhi_counters(&ru_info, proc->frame_rx, proc->tti_rx); if (proc->tti_rx != *slot) { LOG_E(HW, "Received Time doesn't correspond to the time we think it is (slot mismatch, received %d.%d, expected %d.%d)\n", diff --git a/radio/fhi_72/oran_isolate.h b/radio/fhi_72/oran_isolate.h index 450115fcff..24ee524656 100644 --- a/radio/fhi_72/oran_isolate.h +++ b/radio/fhi_72/oran_isolate.h @@ -40,6 +40,8 @@ typedef struct ru_info_s { c16_t (*prach_buf)[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX][NR_PRACH_SEQ_LEN_L]; } ru_info_t; +void print_fhi_counters(ru_info_t *ru, const int frame, const int slot); + /** @brief Reads RX data PUSCH of next slot. * * @param ru pointer to structure keeping pointers to OAI data. From c5e1c4f34f445b6672d5db1a2305a15531710302 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 28 May 2025 09:56:55 +0000 Subject: [PATCH 12/17] feat(CI): Build FHI with K release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the dockerfiles for building DPDK 24.11.4 and xran K release. Signed-off-by: Teodora Vladić --- docker/Dockerfile.base.rhel9 | 4 +++- docker/Dockerfile.build.fhi72.native_arm.ubuntu | 15 ++++++++------- docker/Dockerfile.build.fhi72.rhel9 | 13 +++++++------ docker/Dockerfile.build.fhi72.ubuntu | 15 ++++++++------- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/docker/Dockerfile.base.rhel9 b/docker/Dockerfile.base.rhel9 index 7ed085faf5..d838b038f9 100644 --- a/docker/Dockerfile.base.rhel9 +++ b/docker/Dockerfile.base.rhel9 @@ -45,7 +45,9 @@ RUN rm -f /etc/rhsm-host && \ gcc-toolset-13-gcc-c++ \ # python3-pip and pyyaml are used for conf template generation python3-pip && \ - pip3 install --ignore-installed pyyaml && \ + pip3 install --ignore-installed \ + pyyaml \ + pyelftools && \ echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \ echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf diff --git a/docker/Dockerfile.build.fhi72.native_arm.ubuntu b/docker/Dockerfile.build.fhi72.native_arm.ubuntu index 8aa77c3b33..fea4a3699c 100644 --- a/docker/Dockerfile.build.fhi72.native_arm.ubuntu +++ b/docker/Dockerfile.build.fhi72.native_arm.ubuntu @@ -9,6 +9,7 @@ FROM ran-base:latest AS ran-base +ARG xran_VERSION=11.1.1 ARG E2AP_VERSION=E2AP_V3 ARG KPM_VERSION=KPM_V3_00 ENV DEBIAN_FRONTEND=noninteractive @@ -20,7 +21,8 @@ RUN apt-get update && \ wget \ xz-utils \ pkg-config \ - libnuma-dev && \ + libnuma-dev \ + python3-pyelftools && \ rm -rf /var/lib/apt/lists/* RUN rm -Rf /oai-ran @@ -28,9 +30,9 @@ WORKDIR /oai-ran COPY . . ## Download and build DPDK -RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \ - tar -xvf dpdk-20.11.9.tar.xz && \ - cd dpdk-stable-20.11.9 && \ +RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-24.11.4.tar.xz && \ + tar -xf dpdk-24.11.4.tar.xz && \ + cd dpdk-stable-24.11.4 && \ meson setup -Dmachine=default build && \ ninja -C build && \ ninja install -C build @@ -38,10 +40,9 @@ RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \ ## Build Fronthaul library RUN git clone https://github.com/openairinterface/o-du-phy.git /opt/phy && \ cd /opt/phy && \ - git checkout oran_f_release_v1.0 &&\ - git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch && \ + git checkout $xran_VERSION &&\ cd /opt/phy/fhi_lib/lib && \ - TARGET=armv8 WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-20.11.9/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1 + TARGET=armv8 WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-24.11.4/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1 ## Build Arm RAN Acceleration Library RUN git clone https://git.gitlab.arm.com/networking/ral.git /opt/ral && \ diff --git a/docker/Dockerfile.build.fhi72.rhel9 b/docker/Dockerfile.build.fhi72.rhel9 index 315d1367bb..ec26015da2 100644 --- a/docker/Dockerfile.build.fhi72.rhel9 +++ b/docker/Dockerfile.build.fhi72.rhel9 @@ -14,10 +14,12 @@ RUN rm -Rf /oai-ran WORKDIR /oai-ran COPY . . +ARG xran_VERSION=11.1.1 + ## Download and build DPDK -RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \ - tar -xvf dpdk-20.11.9.tar.xz && \ - cd dpdk-stable-20.11.9 && \ +RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-24.11.4.tar.xz && \ + tar -xf dpdk-24.11.4.tar.xz && \ + cd dpdk-stable-24.11.4 && \ meson build && \ ninja -C build && \ ninja install -C build @@ -25,10 +27,9 @@ RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \ ## Build Fronthaul library RUN git clone https://github.com/openairinterface/o-du-phy.git /opt/phy && \ cd /opt/phy && \ - git checkout oran_f_release_v1.0 &&\ - git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch && \ + git checkout $xran_VERSION &&\ cd /opt/phy/fhi_lib/lib && \ - WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-20.11.9/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1 + WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-24.11.4/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1 FROM ran-base AS ran-build-fhi72 ARG E2AP_VERSION=E2AP_V3 diff --git a/docker/Dockerfile.build.fhi72.ubuntu b/docker/Dockerfile.build.fhi72.ubuntu index 3375be7ff7..d9149171fb 100644 --- a/docker/Dockerfile.build.fhi72.ubuntu +++ b/docker/Dockerfile.build.fhi72.ubuntu @@ -9,6 +9,7 @@ FROM ran-base:latest AS ran-base +ARG xran_VERSION=11.1.1 ARG E2AP_VERSION=E2AP_V3 ARG KPM_VERSION=KPM_V3_00 ENV DEBIAN_FRONTEND=noninteractive @@ -20,7 +21,8 @@ RUN apt-get update && \ wget \ xz-utils \ pkg-config \ - libnuma-dev && \ + libnuma-dev \ + python3-pyelftools && \ rm -rf /var/lib/apt/lists/* RUN rm -Rf /oai-ran @@ -28,9 +30,9 @@ WORKDIR /oai-ran COPY . . ## Download and build DPDK -RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \ - tar -xvf dpdk-20.11.9.tar.xz && \ - cd dpdk-stable-20.11.9 && \ +RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-24.11.4.tar.xz && \ + tar -xf dpdk-24.11.4.tar.xz && \ + cd dpdk-stable-24.11.4 && \ meson build && \ ninja -C build && \ ninja install -C build @@ -38,10 +40,9 @@ RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \ ## Build Fronthaul library RUN git clone https://github.com/openairinterface/o-du-phy.git /opt/phy && \ cd /opt/phy && \ - git checkout oran_f_release_v1.0 &&\ - git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch && \ + git checkout $xran_VERSION &&\ cd /opt/phy/fhi_lib/lib && \ - WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-20.11.9/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1 + WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-24.11.4/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1 FROM ran-base AS ran-build-fhi72 ## Build and install OAI From 82f57789a5869abebd6beb7a6cfa4d4ecd875319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Wed, 22 Apr 2026 11:45:53 +0200 Subject: [PATCH 13/17] Revert "feat(FHI72): Fix lcore count on Arm targets" This reverts commit 8d78c9751329a6154a1db9c1c6bbb6d3715c28f9. Not relevant for DPDK >= 24. --- docker/Dockerfile.build.fhi72.native_arm.ubuntu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile.build.fhi72.native_arm.ubuntu b/docker/Dockerfile.build.fhi72.native_arm.ubuntu index fea4a3699c..eb3dd4b7c7 100644 --- a/docker/Dockerfile.build.fhi72.native_arm.ubuntu +++ b/docker/Dockerfile.build.fhi72.native_arm.ubuntu @@ -33,7 +33,7 @@ COPY . . RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-24.11.4.tar.xz && \ tar -xf dpdk-24.11.4.tar.xz && \ cd dpdk-stable-24.11.4 && \ - meson setup -Dmachine=default build && \ + meson build && \ ninja -C build && \ ninja install -C build From 9fb78e1b34bae11666f201843bf24736e60140b3 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Wed, 4 Jun 2025 16:42:23 +0200 Subject: [PATCH 14/17] Install libatomic in FHI72 gNB images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libatomic is required by DPDK 24.11.4 Signed-off-by: Teodora Vladić --- docker/Dockerfile.gNB.fhi72.rhel9 | 1 + docker/Dockerfile.gNB.fhi72.rocky | 1 + docker/Dockerfile.gNB.fhi72.ubuntu | 1 + 3 files changed, 3 insertions(+) diff --git a/docker/Dockerfile.gNB.fhi72.rhel9 b/docker/Dockerfile.gNB.fhi72.rhel9 index 1fc3d18d37..d1afe4ffd4 100644 --- a/docker/Dockerfile.gNB.fhi72.rhel9 +++ b/docker/Dockerfile.gNB.fhi72.rhel9 @@ -41,6 +41,7 @@ RUN rm -f /etc/rhsm-host && \ python3-pip \ net-tools \ iputils \ + libatomic \ yaml-cpp-devel && \ pip3 install six && \ pip3 install requests && \ diff --git a/docker/Dockerfile.gNB.fhi72.rocky b/docker/Dockerfile.gNB.fhi72.rocky index 09ead432e8..3a25062fea 100644 --- a/docker/Dockerfile.gNB.fhi72.rocky +++ b/docker/Dockerfile.gNB.fhi72.rocky @@ -18,6 +18,7 @@ ENV TZ=Europe/Paris RUN dnf update -y && \ dnf install -y \ procps-ng \ + libatomic \ libXpm \ libX11 \ lksctp-tools \ diff --git a/docker/Dockerfile.gNB.fhi72.ubuntu b/docker/Dockerfile.gNB.fhi72.ubuntu index 132f22c9a6..84758df455 100644 --- a/docker/Dockerfile.gNB.fhi72.ubuntu +++ b/docker/Dockerfile.gNB.fhi72.ubuntu @@ -41,6 +41,7 @@ RUN apt-get update && \ python3 \ python3-six \ python3-requests \ + libatomic1 \ libyaml-cpp-dev && \ # if the --sanitize option was used to build, additional packages are required /bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \ From 9a2a31351593f358e445eae2bd19bfa26b44ed7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Fri, 3 Apr 2026 12:14:24 +0200 Subject: [PATCH 15/17] Make debug logging for PRACH nRxPkt = 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit was tested with MicroAmp FR2 with 2x2 MIMO, where PRACH Rx antennas used is 1. OAI L1 sets the number of PRACH antennas to be the same as for PUSCH. Ideally, this should be properly fixed. In the meantime, I modified the logging to debug to reduce noise. Signed-off-by: Teodora Vladić --- radio/fhi_72/oaioran.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 94bb5dd259..d005a8a518 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -500,7 +500,7 @@ int xran_fh_rx_prach_read_slot(PHY_VARS_gNB *gNB, ru_info_t *ru, int *frame, int int32_t nRxPkt = oran_sync_info.nRxPkt[cc_id][aa][sym_idx]; #endif if (nRxPkt == 0) { - LOG_E(HW, "read_prach %d.%d.%d saa = %d: nRxPkt = 0!\n", *frame, *slot, sym_idx, aa); + LOG_D(HW, "read_prach %d.%d.%d saa = %d: nRxPkt = 0!\n", *frame, *slot, sym_idx, aa); memset(&dst[sym_idx], 0, N_ZC * 2 * sizeof(*dst)); continue; } else if (nRxPkt > 1) { // protection From 7af713a1d1f39d30430f97b3c82d23ba357f3198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Wed, 15 Apr 2026 14:47:46 +0200 Subject: [PATCH 16/17] Remove polling support for fronthaul interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Teodora Vladić --- doc/ORAN_FHI7.2_Tutorial.md | 13 ----- radio/fhi_72/CMakeLists.txt | 2 - radio/fhi_72/README.md | 6 +- radio/fhi_72/oaioran.c | 108 +----------------------------------- 4 files changed, 5 insertions(+), 124 deletions(-) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index e766aacbe8..2633396e0b 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -501,19 +501,6 @@ cmake .. -GNinja -DOAI_FHI72=ON -Dxran_DOWNLOAD=ON ninja nr-softmodem oran_fhlib_5g params_libconfig ``` -Note that in tags 2025.w06 and prior, the FHI72 driver used polling to wait for -the next slot. This is inefficient as it burns CPU time, and has been replaced -with a more efficient mechanism. Nevertheless, if you experience problems that -did not occur previously, it is possible to re-enable polling, either with -`build_oai` like this - - ./build_oai --gNB --ninja -t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=$HOME/phy/fhi_lib/lib --cmake-opt -DOAI_FHI72_USE_POLLING=ON - -or with `cmake` like so - - cmake .. -GNinja -DOAI_FHI72=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib -DOAI_FHI72_USE_POLLING=ON - ninja oran_fhlib_5g - ## Configuration RU and DU configurations have a circular dependency: you have to configure DU MAC address in the RU configuration and the RU MAC address, VLAN and Timing advance parameters in the DU configuration. diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index 9f09ba8168..549fe0b2ed 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -85,8 +85,6 @@ if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") target_link_libraries(oran_fhlib_5g PRIVATE armral) endif() -add_boolean_option(OAI_FHI72_USE_POLLING OFF "Enable polling in FHI72 driver" ON) - message(STATUS "Building FHI72 CUS library") set_target_properties(oran_fhlib_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/radio/fhi_72/README.md b/radio/fhi_72/README.md index e161ceaf40..a631e72641 100644 --- a/radio/fhi_72/README.md +++ b/radio/fhi_72/README.md @@ -43,8 +43,8 @@ optionally compresses IQ data, then writes it into IQ buffers of xran. For PUSCH/PRACH, `oran_fh_if4p5_south_in()` calls `xran_fh_rx_read_slot()`/ `xran_fh_rx_prach_read_slot()` that blocks and waits for the next slot. -This is done through either a message queue, or through polling, which in both -cases depends on xran calling the callbacks `oai_xran_fh_rx_callback()`/ -`oai_xran_fh_rx_prach_callback()` as installed during xran initialization. +This is done through a message queue which depends on xran calling the callbacks +`oai_xran_fh_rx_callback()`/`oai_xran_fh_rx_prach_callback()` as installed during +xran initialization. Once unblocked, it reads first PUSCH data, then PRACH data, before returning to OAI. diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index d005a8a518..6aaaa0d8fb 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -29,10 +29,6 @@ #define N_SC_PER_PRB 12 -#if OAI_FHI72_USE_POLLING -#define USE_POLLING -#endif - // Declare variable useful for the send buffer function volatile bool first_call_set = false; @@ -43,7 +39,6 @@ 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; #define MAX_QUEUE_LENGTH_NO_JUMP 3 atomic_int xran_queue_length = 0; @@ -51,13 +46,6 @@ atomic_int xran_queue_prach_length = 0; #if defined K_RELEASE extern notifiedFIFO_t oran_sync_fifo_prach; #endif -#else -volatile oran_sync_info_t oran_sync_info = {0}; -#if defined K_RELEASE -volatile oran_sync_info_t oran_sync_info_prach = {0}; -volatile bool prach_rx_awaiting = false; -#endif -#endif /* Prints TX_TOTAL, RX_TOTAL, RX_ON_TIME, RX_ERR_DROP counters every 128 frames. */ void print_fhi_counters(ru_info_t *ru, const int frame, const int slot) @@ -116,8 +104,7 @@ void print_fhi_counters(ru_info_t *ru, const int frame, const int slot) /** @details xran-specific callback, called when all packets for given CC and * 1/4, 1/2, 3/4, all symbols of a slot arrived. Currently, only used to get * timing information and unblock another thread in xran_fh_rx_read_slot() - * through either a message queue, or writing in global memory with polling, on - * a full slot boundary. */ + * through a message queue on a full slot boundary. */ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status #if defined K_RELEASE , uint8_t mu @@ -191,7 +178,6 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status 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 = NotifiedFifoData(req); info->tti = tti; @@ -218,28 +204,6 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status LOG_D(HW, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); atomic_fetch_add(&xran_queue_length, 1); pushNotifiedFIFO(&oran_sync_fifo, req); -#else - LOG_D(HW, "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; -#if defined K_RELEASE - oran_sync_info.mu = mu; - - oran_buf_list_t *bufs = get_xran_buffers(ru_id); - struct xran_fh_config *fh_config = get_xran_fh_config(ru_id); - for (uint16_t cc_id = 0; cc_id < 1 /* fh_config->nCC */; cc_id++) { // OAI does not support multiple CC yet. - for(uint32_t ant_id = 0; ant_id < fh_config->neAxc; ant_id++) { - struct xran_prb_map *pRbMap = (struct xran_prb_map *)bufs->dstcp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; - AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMap == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id); - for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) { - oran_sync_info.nRxPkt[cc_id][ant_id][sym_id] = pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt; - pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt = 0; - } - } - } -#endif -#endif } else LOG_E(HW, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); last_slot = slot2; @@ -295,20 +259,12 @@ void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status 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_prach, NULL); oran_sync_info_t *info = NotifiedFifoData(req); info->tti = tti; info->sl = slot2; info->f = frame; info->mu = mu; -#else - LOG_D(HW, "Writing PRACH slot %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); - oran_sync_info_prach.tti = tti; - oran_sync_info_prach.sl = slot2; - oran_sync_info_prach.f = frame; - oran_sync_info_prach.mu = mu; -#endif struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag; uint32_t tti = callback_tag->slotiId; uint32_t ru_id = callback_tag->oXuId; @@ -321,23 +277,15 @@ void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMapPrach == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id); for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) { AssertFatal(pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt <= 1, "PRACH segmentation is not supported\n"); -#ifndef USE_POLLING info->nRxPkt[cc_id][ant_id][sym_id] = pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt; -#else - oran_sync_info_prach.nRxPkt[cc_id][ant_id][sym_id] = pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt; -#endif pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt = 0; } } } } -#ifndef USE_POLLING LOG_D(HW, "Push PRACH slot %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); atomic_fetch_add(&xran_queue_prach_length, 1); pushNotifiedFIFO(&oran_sync_fifo_prach, req); -#else - prach_rx_awaiting = true; -#endif } else LOG_E(HW, "Cannot Push PRACH slot %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); last_slot = slot2; @@ -372,7 +320,6 @@ int oai_physide_dl_tti_call_back(void *param int xran_fh_rx_prach_read_slot(PHY_VARS_gNB *gNB, ru_info_t *ru, int *frame, int *slot) { #if defined K_RELEASE -#ifndef USE_POLLING // pull next even from oran_sync_fifo_prach if any notifiedFIFO_elt_t *res = pullNotifiedFIFO(&oran_sync_fifo_prach); atomic_fetch_sub(&xran_queue_prach_length, 1); @@ -399,29 +346,6 @@ int xran_fh_rx_prach_read_slot(PHY_VARS_gNB *gNB, ru_info_t *ru, int *frame, int *frame = info->f; uint8_t mu = info->mu; delNotifiedFIFO_elt(res); -#else -#error "POLLING is not supported for K release unless you know how to fix the race condition on prach_rx_awaiting" - if (!prach_rx_awaiting) { - return (0); - } else { - prach_rx_awaiting = false; - } - *slot = oran_sync_info_prach.sl; - *frame = oran_sync_info_prach.f; - uint8_t mu = oran_sync_info_prach.mu; - uint32_t tti_in = oran_sync_info_prach.tti; - - static int last_slot = -1; - LOG_D(HW, "oran slot %d, last_slot %d\n", *slot, last_slot); - int cnt = 0; - // while (*slot == last_slot) { - while (tti_in == oran_sync_info_prach.tti) { - //*slot = oran_sync_info.sl; - cnt++; - } - LOG_D(HW, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot); - last_slot = *slot; -#endif #endif prach_item_t p; @@ -494,11 +418,7 @@ int xran_fh_rx_prach_read_slot(PHY_VARS_gNB *gNB, ru_info_t *ru, int *frame, int #if defined K_RELEASE struct xran_prb_map * pPrbMap = (struct xran_prb_map *)bufs->prachdstdecomp[aa % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; struct xran_rx_packet_ctl *p_rx_packet_ctl = &pPrbMap->sFrontHaulRxPacketCtrl[sym_idx]; -#ifndef USE_POLLING int32_t nRxPkt = info->nRxPkt[cc_id][aa][sym_idx]; -#else - int32_t nRxPkt = oran_sync_info.nRxPkt[cc_id][aa][sym_idx]; -#endif if (nRxPkt == 0) { LOG_D(HW, "read_prach %d.%d.%d saa = %d: nRxPkt = 0!\n", *frame, *slot, sym_idx, aa); memset(&dst[sym_idx], 0, N_ZC * 2 * sizeof(*dst)); @@ -640,7 +560,6 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) int idx = 0; static int outcnt = 0; -#ifndef USE_POLLING // pull next event from oran_sync_fifo notifiedFIFO_elt_t *res = pullNotifiedFIFO(&oran_sync_fifo); atomic_fetch_sub(&xran_queue_length, 1); @@ -669,25 +588,6 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) uint8_t mu = info->mu; #endif delNotifiedFIFO_elt(res); -#else - *slot = oran_sync_info.sl; - *frame = oran_sync_info.f; -#if defined K_RELEASE - uint8_t mu = oran_sync_info.mu; -#endif - uint32_t tti_in = oran_sync_info.tti; - - static int last_slot = -1; - LOG_D(HW, "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(HW, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot); - last_slot = *slot; -#endif // return(0); struct xran_fh_config *fh_cfg = get_xran_fh_config(0); @@ -743,11 +643,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) struct xran_rx_packet_ctl *p_rx_packet_ctl = &pRbMap->sFrontHaulRxPacketCtrl[sym_idx]; uint32_t one_rb_size = (((pRbElm->iqWidth == 0) || (pRbElm->iqWidth == 16)) ? (N_SC_PER_PRB * 2 * 2) : (3 * pRbElm->iqWidth + 1)); -#ifndef USE_POLLING - int32_t nRxPkt = info->nRxPkt[cc_id][ant_id][sym_idx]; -#else - int32_t nRxPkt = oran_sync_info.nRxPkt[cc_id][ant_id][sym_idx]; -#endif + int32_t nRxPkt = info->nRxPkt[cc_id][ant_id][sym_idx]; LOG_D(HW, "nRxPkt %d\n", nRxPkt); for (int pkt_idx = 0; pkt_idx < nRxPkt; pkt_idx++) { uint8_t *pData; From 3afda6aea1ac4f2a8c37d906c0bd34ed93126077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Thu, 23 Apr 2026 10:09:29 +0200 Subject: [PATCH 17/17] Add a warning for F release support Similarly to: https://gitlab.eurecom.fr/oai/openairinterface5g/-/merge_requests/3936/diffs#57257e70cd9cf83d562fe56bd6d173cb45785f74_466_422 --- radio/fhi_72/oran-init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/radio/fhi_72/oran-init.c b/radio/fhi_72/oran-init.c index c5acd26c71..8d1e01023a 100644 --- a/radio/fhi_72/oran-init.c +++ b/radio/fhi_72/oran-init.c @@ -488,6 +488,7 @@ void *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_conf exit(-1); } #elif defined F_RELEASE + LOG_W(HW, "Please be aware that F release support will be removed in the future. Consider switching to K release.\n"); oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &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);