diff --git a/cmake_targets/tools/MODULES/Findarmral.cmake b/cmake_targets/tools/MODULES/Findarmral.cmake new file mode 100644 index 0000000000..79407ffc91 --- /dev/null +++ b/cmake_targets/tools/MODULES/Findarmral.cmake @@ -0,0 +1,123 @@ +# +# Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The OpenAirInterface Software Alliance licenses this file to You under +# the OAI Public License, Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.openairinterface.org/?page_id=698 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ------------------------------------------------------------------------------ +# For more information about the OpenAirInterface (OAI) Software Alliance: +# contact@openairinterface.org +# + +# FindArmral +# ------- +# +# Finds the armral library. +# the version is currently hardcoded to 25.01 +# +# Optional options +# ^^^^^^^^^^^^^^^^ +# +# ``armral_LOCATION`` +# The location of the library. +# +# Imported Targets +# ^^^^^^^^^^^^^^^^ +# +# This module provides the following imported targets, if found: +# +# ``armral`` +# The armral library +# +# Result Variables +# ^^^^^^^^^^^^^^^^ +# +# This will define the following variables: +# +# ``armral_FOUND`` +# True if the system has the armral library. +# ``armral_VERSION`` +# The version of the armral library which was found. +# ``armral_INCLUDE_DIRS`` +# Include directories needed to use armral. +# ``armral_LIBRARIES`` +# Libraries needed to link to armral. +# +# Cache Variables +# ^^^^^^^^^^^^^^^ +# +# The following cache variables may also be set: +# +# ``armral_INCLUDE_DIR`` +# The directory containing ``armral.h``. +# ``armral_LIBRARY`` +# The path to the armral library. + +option(armral_LOCATION "directory of ArmRAL library" "") +if (NOT armral_LOCATION) + set(armral_LOCATION "/usr/local") +endif() +if (NOT EXISTS ${armral_LOCATION}) + message(FATAL_ERROR "no such directory: ${armral_LOCATION}") +endif() + +find_path(armral_INCLUDE_DIR + NAMES + armral.h + HINTS ${armral_LOCATION} + PATH_SUFFIXES include + NO_DEFAULT_PATH +) +if (NOT armral_INCLUDE_DIR) + message(FATAL_ERROR "could not detect armral header at ${armral_LOCATION}/include") +endif() + +find_library(armral_LIBRARY + NAMES armral + HINTS ${armral_LOCATION} + PATH_SUFFIXES lib build + NO_DEFAULT_PATH +) +if (NOT armral_LIBRARY) + message(FATAL_ERROR "could not detect armral build artifacts at neither ${armral_LOCATION}/lib nor ${armral_LOCATION}/build") +endif() + +# No way to retrieve the version from header or library +set(armral_VERSION 25.01) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(armral + FOUND_VAR armral_FOUND + REQUIRED_VARS + armral_LIBRARY + armral_INCLUDE_DIR + VERSION_VAR armral_VERSION +) + +if(armral_FOUND) + set(armral_LIBRARIES ${armral_LIBRARY}) + set(armral_INCLUDE_DIRS ${armral_INCLUDE_DIR}) +endif() + +if(armral_FOUND AND NOT TARGET armral) + add_library(armral UNKNOWN IMPORTED) + set_target_properties(armral PROPERTIES + IMPORTED_LOCATION "${armral_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${armral_INCLUDE_DIRS}" + ) +endif() + +mark_as_advanced( + armral_INCLUDE_DIR + armral_LIBRARY +) diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index 4a9064e661..cec59d38ad 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -32,6 +32,11 @@ add_compile_options(-Wno-packed-not-aligned) set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native") target_link_libraries(oran_fhlib_5g PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa) target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS}) +if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + find_package(armral REQUIRED) + target_sources(oran_fhlib_5g PRIVATE armral_bfp_compression.c) + target_link_libraries(oran_fhlib_5g PRIVATE armral) +endif() add_boolean_option(OAI_FHI72_USE_POLLING OFF "Enable polling in FHI72 driver" ON) diff --git a/radio/fhi_72/armral_bfp_compression.c b/radio/fhi_72/armral_bfp_compression.c new file mode 100644 index 0000000000..a02d4a4106 --- /dev/null +++ b/radio/fhi_72/armral_bfp_compression.c @@ -0,0 +1,116 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file radio/fhi_72/armral_bfp_compression.c + * \brief BFP compression for the O-RAN 7.2 FrontHaul Interface for Arm systems using the Arm RAN Acceleration Library + * \author Romain Beurdouche + * \date 2025 + * \company EURECOM + * \email romain.beurdouche@eurecom.fr + * \note ArmRAL available at https://git.gitlab.arm.com/networking/ral.git + * \warning + */ + +#include "armral.h" +#include + +#include "armral_bfp_compression.h" +#include "common/utils/LOG/log.h" + +/** + * The function operates on a fixed block size of one Physical Resource Block + * (PRB). Each block consists of 12 16-bit complex resource elements. Each block + * taken as input is compressed into 24 samples with a common unsigned scaling factor. + * + * @param[in] iq_width Width in bits of compressed samples. + * @param[in] n_prb The number of input resource blocks. + * @param[in] src Points to the input complex samples sequence. + * @param[out] dst Points to the output compressed data. + */ +void armral_bfp_compression(uint32_t iq_width, uint32_t n_prb, int16_t *src, int8_t *dst) +{ + armral_status ret = ARMRAL_ARGUMENT_ERROR; + switch (iq_width) { + case 8: + ret = armral_block_float_compr_8bit(n_prb, (armral_cmplx_int16_t *)src, (armral_compressed_data_8bit *)dst, NULL); + if (unlikely(ret != ARMRAL_SUCCESS)) { + LOG_E(HW, "armral_block_scaling_compr_8bit returned an error: %d\n", (int)ret); + } + break; + + case 9: + ret = armral_block_float_compr_9bit(n_prb, (armral_cmplx_int16_t *)src, (armral_compressed_data_9bit *)dst, NULL); + if (unlikely(ret != ARMRAL_SUCCESS)) { + LOG_E(HW, "armral_block_scaling_compr_9bit returned an error: %d\n", (int)ret); + } + break; + + case 14: + ret = armral_block_float_compr_14bit(n_prb, (armral_cmplx_int16_t *)src, (armral_compressed_data_14bit *)dst, NULL); + if (unlikely(ret != ARMRAL_SUCCESS)) { + LOG_E(HW, "armral_block_scaling_compr_14bit returned an error: %d\n", (int)ret); + } + break; + + default: + LOG_E(HW, "Unsupported IQ width in BFP compression: %d\n", iq_width); + } +} + +/** + * The function operates on a fixed block size of one Physical Resource Block + * (PRB). Each block consists of 12 compressed complex resource elements. + * Each block taken as input is expanded into 12 16-bit complex samples. + * + * @param[in] iq_width Width in bits of compressed samples. + * @param[in] n_prb The number of input resource blocks. + * @param[in] src Points to the input compressed data. + * @param[out] dst Points to the output complex samples sequence. + */ +void armral_bfp_decompression(uint32_t iq_width, uint32_t n_prb, int8_t *src, int16_t *dst) +{ + armral_status ret = ARMRAL_ARGUMENT_ERROR; + switch (iq_width) { + case 8: + ret = armral_block_float_decompr_8bit(n_prb, (armral_compressed_data_8bit *)src, (armral_cmplx_int16_t *)dst, NULL); + if (unlikely(ret != ARMRAL_SUCCESS)) { + LOG_E(HW, "armral_block_scaling_decompr_8bit returned an error: %d\n", (int)ret); + } + break; + + case 9: + ret = armral_block_float_decompr_9bit(n_prb, (armral_compressed_data_9bit *)src, (armral_cmplx_int16_t *)dst, NULL); + if (unlikely(ret != ARMRAL_SUCCESS)) { + LOG_E(HW, "armral_block_scaling_decompr_9bit returned an error: %d\n", (int)ret); + } + break; + + case 14: + ret = armral_block_float_decompr_14bit(n_prb, (armral_compressed_data_14bit *)src, (armral_cmplx_int16_t *)dst, NULL); + if (unlikely(ret != ARMRAL_SUCCESS)) { + LOG_E(HW, "armral_block_scaling_decompr_14bit returned an error: %d\n", (int)ret); + } + break; + + default: + LOG_E(HW, "Unsupported IQ width in BFP decompression: %d\n", iq_width); + } +} diff --git a/radio/fhi_72/armral_bfp_compression.h b/radio/fhi_72/armral_bfp_compression.h new file mode 100644 index 0000000000..22cee0aa8b --- /dev/null +++ b/radio/fhi_72/armral_bfp_compression.h @@ -0,0 +1,59 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file radio/fhi_72/armral_bfp_compression.h + * \brief BFP compression for the O-RAN 7.2 FrontHaul Interface for Arm systems using the Arm RAN Acceleration Library + * \author Romain Beurdouche + * \date 2025 + * \company EURECOM + * \email romain.beurdouche@eurecom.fr + * \note ArmRAL available at https://git.gitlab.arm.com/networking/ral.git + * \warning + */ + +#ifndef __ARMRAL_BFP_COMPRESSION_H__ +#define __ARMRAL_BFP_COMPRESSION_H__ + +/** + * The function operates on a fixed block size of one Physical Resource Block + * (PRB). Each block consists of 12 16-bit complex resource elements. Each block + * taken as input is compressed into 24 samples with a common unsigned scaling factor. + * + * @param[in] iq_width Width in bits of compressed samples. + * @param[in] n_prb The number of input resource blocks. + * @param[in] src Points to the input complex samples sequence. + * @param[out] dst Points to the output compressed data. + */ +void armral_bfp_compression(uint32_t iq_width, uint32_t n_prb, int16_t *src, int8_t *dst); + +/** + * The function operates on a fixed block size of one Physical Resource Block + * (PRB). Each block consists of 12 compressed complex resource elements. + * Each block taken as input is expanded into 12 16-bit complex samples. + * + * @param[in] iq_width Width in bits of compressed samples. + * @param[in] n_prb The number of input resource blocks. + * @param[in] src Points to the input compressed data. + * @param[out] dst Points to the output complex samples sequence. + */ +void armral_bfp_decompression(uint32_t iq_width, uint32_t n_prb, int8_t *src, int16_t *dst); + +#endif diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index afa6384741..7ac4998e40 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -24,6 +24,7 @@ #include #include "xran_fh_o_du.h" #include "xran_compression.h" +#include "armral_bfp_compression.h" #if defined(__arm__) || defined(__aarch64__) #else @@ -215,12 +216,14 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) } } } else if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_BLKFLOAT) { - struct xranlib_decompress_request bfp_decom_req = {}; - struct xranlib_decompress_response bfp_decom_rsp = {}; int16_t local_dst[12 * 2 * N_SC_PER_PRB] __attribute__((aligned(64))); +#if defined(__i386__) || defined(__x86_64__) + struct xranlib_decompress_request bfp_decom_req = {}; + struct xranlib_decompress_response bfp_decom_rsp = {}; int payload_len = (3 * ru_conf->iqWidth_PRACH + 1) * 12; // 12 = closest number of PRBs to 139 REs + bfp_decom_req.data_in = (int8_t *)src; bfp_decom_req.numRBs = 12; // closest number of PRBs to 139 REs bfp_decom_req.len = payload_len; @@ -230,6 +233,11 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) bfp_decom_rsp.data_out = (int16_t *)local_dst; bfp_decom_rsp.len = 0; xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp); +#elif defined(__arm__) || defined(__aarch64__) + armral_bfp_decompression(ru_conf->iqWidth_PRACH, 12, (int8_t *)src, (int16_t *)local_dst); +#else + AssertFatal(1 == 0, "BFP decompression not supported on this architecture"); +#endif // note: this is hardwired for 139 point PRACH sequence, kbar=2 if (sym_idx == 0) // for (idx = 0; idx < (139 * 2); idx++) @@ -380,8 +388,6 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) uint32_t idxElm = 0; uint8_t *src = (uint8_t *)ptr; - int16_t payload_len = 0; - LOG_D(HW, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm); for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) { @@ -412,10 +418,12 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) memcpy((void *)dst2, (void *)local_dst, neg_len * 4); memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4); } else if (pRbElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) { +#if defined(__i386__) || defined(__x86_64__) struct xranlib_decompress_request bfp_decom_req = {}; struct xranlib_decompress_response bfp_decom_rsp = {}; - payload_len = (3 * pRbElm->iqWidth + 1) * pRbElm->nRBSize; + int16_t payload_len = (3 * pRbElm->iqWidth + 1) * pRbElm->nRBSize; + bfp_decom_req.data_in = (int8_t *)src; bfp_decom_req.numRBs = pRbElm->nRBSize; bfp_decom_req.len = payload_len; @@ -426,6 +434,11 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) bfp_decom_rsp.len = 0; xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp); +#elif defined(__arm__) || defined(__aarch64__) + armral_bfp_decompression(pRbElm->iqWidth, pRbElm->nRBSize, (int8_t *)src, (int16_t *)local_dst); +#else + AssertFatal(1 == 0, "BFP compression not supported on this architecture"); +#endif memcpy((void *)dst2, (void *)local_dst, neg_len * 4); memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4); outcnt++; @@ -552,9 +565,12 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) for (idx = 0; idx < (pos_len + neg_len) * 2; idx++) ((uint16_t *)dst16)[idx] = htons(((uint16_t *)local_src)[idx]); } else if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) { + payload_len = (3 * p_prbMapElm->iqWidth + 1) * p_prbMapElm->nRBSize; + +#if defined(__i386__) || defined(__x86_64__) struct xranlib_compress_request bfp_com_req = {}; struct xranlib_compress_response bfp_com_rsp = {}; - payload_len = (3 * p_prbMapElm->iqWidth + 1) * p_prbMapElm->nRBSize; + bfp_com_req.data_in = (int16_t *)local_src; bfp_com_req.numRBs = p_prbMapElm->nRBSize; bfp_com_req.len = payload_len; @@ -565,6 +581,11 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) bfp_com_rsp.len = 0; xranlib_compress_avx512(&bfp_com_req, &bfp_com_rsp); +#elif defined(__arm__) || defined(__aarch64__) + armral_bfp_compression(p_prbMapElm->iqWidth, p_prbMapElm->nRBSize, (int16_t *)local_src, (int8_t *)dst); +#else + AssertFatal(1 == 0, "BFP compression not supported on this architecture"); +#endif } else { printf("p_prbMapElm->compMethod == %d is not supported\n", p_prbMapElm->compMethod);