Add O-RAN 7.2 FHI library

- Add the O-RAN 7.2 FHI library, interfacing with OSC xRAN library (E
  release)
- Add Findxran.cmake to detect the library and headers, including
  version information
- Test for numa and DPDK presence
- Add patch for OSC xRAN to make interworking possible
- Add sample config files for LiteOn, Benetel, and VVDN units.

Documentation is provided in the next commit.

Co-authored-by: Raymond Knopp <raymond.knopp@eurecom.fr>
Co-authored-by: Cedric Roux <cedric.roux@eurecom.fr>
Co-authored-by: Manish Kumar Singh <manish1.kumar@amd.com>
Co-authored-by: thamizhselvan.k <thamizhselvan.k@vvdntech.in>
Co-authored-by: rajeshwari.p <rajeshwari.p@vvdntech.in>
Co-authored-by: Hongzhi Wang <hongzhi.wang@openairinterface.org>
Co-authored-by: Sofia Pison <Sofia.Pison@eurecom.fr>
This commit is contained in:
Robert Schmidt
2024-01-23 13:50:49 +01:00
co-authored by Raymond Knopp Cedric Roux Manish Kumar Singh thamizhselvan.k rajeshwari.p Hongzhi Wang Sofia Pison
parent eca56653c1
commit baea11c35c
18 changed files with 4123 additions and 7 deletions
+5
View File
@@ -13,6 +13,11 @@ if(OAI_BLADERF)
add_subdirectory(BLADERF)
endif()
add_boolean_option(OAI_FHI72 OFF "Activate OAI's FHI 7.2 (xran/fhi_lib) driver" OFF)
if(OAI_FHI72)
add_subdirectory(fhi_72)
endif()
add_boolean_option(OAI_IRIS OFF "Activate OAI's IRIS/SoapySDR driver" OFF)
if(OAI_IRIS)
add_subdirectory(IRIS)
+31
View File
@@ -0,0 +1,31 @@
# use env var PKG_CONFIG_PATH to override paths to libdpdk.pc
pkg_check_modules(dpdk REQUIRED libdpdk)
pkg_check_modules(numa REQUIRED numa)
find_package(xran 5.1.1 EXACT REQUIRED) # E release -> 5
# Ignore xran-specific warning: we don't care/can't change the following warning, so suppress
# alignment 1 of 'struct XYZ' is less than 2
add_compile_options(-Wno-packed-not-aligned)
add_library(oran_fhlib_5g MODULE
oran_isolate.c
oaioran.c
oran-config.c
oran-init.c
)
set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native")
target_link_libraries(oran_fhlib_5g PRIVATE xran::xran)
target_link_libraries(oran_fhlib_5g PRIVATE ${dpdk_LINK_LIBRARIES})
target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS})
target_link_libraries(oran_fhlib_5g PRIVATE pthread dl rt m numa)
target_link_libraries(oran_fhlib_5g PRIVATE ${T_LIB})
# TODO: can be removed?
target_include_directories(oran_fhlib_5g PRIVATE ${xran_INCLUDE_DIRS}/../src/)
set_target_properties(oran_fhlib_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
add_custom_command(TARGET oran_fhlib_5g POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g.so liboai_transpro.so
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
+553
View File
@@ -0,0 +1,553 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "xran_fh_o_du.h"
#include "xran_compression.h"
// xran_cp_api.h uses SIMD, but does not include it
#include <immintrin.h>
#include "xran_cp_api.h"
#include "xran_sync_api.h"
#include "oran_isolate.h"
#include "oran-init.h"
#include "xran_common.h"
#include "oaioran.h"
#include <rte_ethdev.h>
#include "oran-config.h" // for g_kbar
#define USE_POLLING 1
// Declare variable useful for the send buffer function
volatile uint8_t first_call_set = 0;
volatile uint8_t first_rx_set = 0;
volatile int first_read_set = 0;
// Variable declaration useful for fill IQ samples from file
#define IQ_PLAYBACK_BUFFER_BYTES (XRAN_NUM_OF_SLOT_IN_TDD_LOOP * N_SYM_PER_SLOT * XRAN_MAX_PRBS * N_SC_PER_PRB * 4L)
/*
int rx_tti;
int rx_sym;
volatile uint32_t rx_cb_tti = 0;
volatile uint32_t rx_cb_frame = 0;
volatile uint32_t rx_cb_subframe = 0;
volatile uint32_t rx_cb_slot = 0;
*/
#define GetFrameNum(tti, SFNatSecStart, numSubFramePerSystemFrame, numSlotPerSubFrame) \
((((uint32_t)tti / ((uint32_t)numSubFramePerSystemFrame * (uint32_t)numSlotPerSubFrame)) + SFNatSecStart) & 0x3FF)
#define GetSlotNum(tti, numSlotPerSfn) ((uint32_t)tti % ((uint32_t)numSlotPerSfn))
int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id);
#include "common/utils/LOG/log.h"
#ifndef USE_POLLING
extern notifiedFIFO_t oran_sync_fifo;
#else
volatile oran_sync_info_t oran_sync_info;
#endif
void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
{
struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag;
uint64_t second;
uint32_t tti;
uint32_t frame;
uint32_t subframe;
uint32_t slot, slot2;
uint32_t rx_sym;
static int32_t last_slot = -1;
static int32_t last_frame = -1;
struct xran_device_ctx *xran_ctx = xran_dev_get_ctx();
const struct xran_fh_init *fh_init = &xran_ctx->fh_init;
int num_ports = fh_init->xran_ports;
static int rx_RU[XRAN_PORTS_NUM][20] = {0};
uint32_t rx_tti = callback_tag->slotiId;
tti = xran_get_slot_idx_from_tti(rx_tti, &frame, &subframe, &slot, &second);
rx_sym = callback_tag->symbol;
uint32_t ru_id = callback_tag->oXuId;
if (rx_sym == 7) {
if (first_call_set) {
if (!first_rx_set) {
LOG_I(NR_PHY, "first_rx is set (num_ports %d)\n", num_ports);
}
first_rx_set = 1;
if (first_read_set == 1) {
slot2 = slot + (subframe << 1);
rx_RU[ru_id][slot2] = 1;
if (last_frame > 0 && frame > 0
&& ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023))))
LOG_E(PHY, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2);
for (int i = 0; i < num_ports; i++) {
if (rx_RU[i][slot2] == 0)
return;
}
for (int i = 0; i < num_ports; i++)
rx_RU[i][slot2] = 0;
if (last_slot == -1 || slot2 != last_slot) {
#ifndef USE_POLLING
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(oran_sync_info_t), 0, &oran_sync_fifo, NULL);
oran_sync_info_t *info = (oran_sync_info_t *)NotifiedFifoData(req);
info->sl = slot2;
info->f = frame;
LOG_D(PHY, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot);
#else
LOG_D(PHY, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
oran_sync_info.tti = tti;
oran_sync_info.sl = slot2;
oran_sync_info.f = frame;
#endif
#ifndef USE_POLLING
pushNotifiedFIFO(&oran_sync_fifo, req);
#else
#endif
} else
LOG_E(PHY, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
last_slot = slot2;
last_frame = frame;
} // first_read_set == 1
} // first_call_set
} // rx_sym == 7
}
void oai_xran_fh_srs_callback(void *pCallbackTag, xran_status_t status)
{
rte_pause();
}
void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status)
{
rte_pause();
}
int oai_physide_dl_tti_call_back(void *param)
{
if (!first_call_set)
printf("first_call set from phy cb first_call_set=%p\n", &first_call_set);
first_call_set = 1;
return 0;
}
int oai_physide_ul_half_slot_call_back(void *param)
{
rte_pause();
return 0;
}
int oai_physide_ul_full_slot_call_back(void *param)
{
rte_pause();
return 0;
}
int read_prach_data(ru_info_t *ru, int frame, int slot)
{
/* calculate tti and subframe_id from frame, slot num */
int tti = 20 * (frame) + (slot);
uint32_t subframe = XranGetSubFrameNum(tti, 2, 10);
uint32_t is_prach_slot = xran_is_prach_slot(0, subframe, (slot % 2));
int sym_idx = 0;
struct xran_device_ctx *xran_ctx = xran_dev_get_ctx();
struct xran_prach_cp_config *pPrachCPConfig = &(xran_ctx->PrachCPConfig);
struct xran_ru_config *ru_conf = &(xran_ctx->fh_cfg.ru_conf);
int nb_rx_per_ru = ru->nb_rx / xran_ctx->fh_init.xran_ports;
/* If it is PRACH slot, copy prach IQ from XRAN PRACH buffer to OAI PRACH buffer */
if (is_prach_slot) {
for (sym_idx = 0; sym_idx < pPrachCPConfig->numSymbol; sym_idx++) {
for (int aa = 0; aa < ru->nb_rx; aa++) {
int16_t *dst, *src;
int idx = 0;
xran_ctx = xran_dev_get_ctx_by_id(aa / nb_rx_per_ru);
dst = ru->prach_buf[aa]; // + (sym_idx*576));
src = (int16_t *)((uint8_t *)xran_ctx->sFHPrachRxBbuIoBufCtrlDecomp[tti % XRAN_N_FE_BUF_LEN][0][aa % nb_rx_per_ru]
.sBufferList.pBuffers[sym_idx]
.pData);
/* convert Network order to host order */
if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) {
if (sym_idx == 0) {
for (idx = 0; idx < 139 * 2; idx++) {
dst[idx] = ((int16_t)ntohs(src[idx + g_kbar]));
}
} else {
for (idx = 0; idx < 139 * 2; idx++) {
dst[idx] += ((int16_t)ntohs(src[idx + g_kbar]));
}
}
} else if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_BLKFLOAT) {
struct xranlib_decompress_request bfp_decom_req;
struct xranlib_decompress_response bfp_decom_rsp;
int16_t local_dst[12 * 2 * N_SC_PER_PRB] __attribute__((aligned(64)));
int payload_len = (3 * ru_conf->iqWidth_PRACH + 1) * 12; // 12 = closest number of PRBs to 139 REs
memset(&bfp_decom_req, 0, sizeof(struct xranlib_decompress_request));
memset(&bfp_decom_rsp, 0, sizeof(struct xranlib_decompress_response));
bfp_decom_req.data_in = (int8_t *)src;
bfp_decom_req.numRBs = 12; // closest number of PRBs to 139 REs
bfp_decom_req.len = payload_len;
bfp_decom_req.compMethod = XRAN_COMPMETHOD_BLKFLOAT;
bfp_decom_req.iqWidth = ru_conf->iqWidth_PRACH;
bfp_decom_rsp.data_out = (int16_t *)local_dst;
bfp_decom_rsp.len = 0;
xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp);
// note: this is hardwired for 139 point PRACH sequence, kbar=2
if (sym_idx == 0) //
for (idx = 0; idx < (139 * 2); idx++)
dst[idx] = local_dst[idx + g_kbar];
else
for (idx = 0; idx < (139 * 2); idx++)
dst[idx] += (local_dst[idx + g_kbar]);
} // COMPMETHOD_BLKFLOAT
} // aa
} // symb_indx
} // is_prach_slot
return (0);
}
int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
{
void *ptr = NULL;
int32_t *pos = NULL;
int idx = 0;
static int last_slot = -1;
first_read_set = 1;
static int64_t old_rx_counter[XRAN_PORTS_NUM] = {0};
static int64_t old_tx_counter[XRAN_PORTS_NUM] = {0};
struct xran_common_counters x_counters[XRAN_PORTS_NUM];
static int outcnt = 0;
#ifndef USE_POLLING
// pull next even from oran_sync_fifo
notifiedFIFO_elt_t *res = pollNotifiedFIFO(&oran_sync_fifo);
while (res == NULL) {
res = pollNotifiedFIFO(&oran_sync_fifo);
}
oran_sync_info_t *info = (oran_sync_info_t *)NotifiedFifoData(res);
*slot = info->sl;
*frame = info->f;
delNotifiedFIFO_elt(res);
#else
LOG_D(PHY, "In xran_fh_rx_read_slot, first_rx_set %d\n", first_rx_set);
while (first_rx_set == 0) {
}
*slot = oran_sync_info.sl;
*frame = oran_sync_info.f;
uint32_t tti_in = oran_sync_info.tti;
LOG_D(PHY, "oran slot %d, last_slot %d\n", *slot, last_slot);
int cnt = 0;
// while (*slot == last_slot) {
while (tti_in == oran_sync_info.tti) {
//*slot = oran_sync_info.sl;
cnt++;
}
LOG_D(PHY, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot);
last_slot = *slot;
#endif
// return(0);
int tti = (*frame * 20) + *slot;
read_prach_data(ru, *frame, *slot);
struct xran_device_ctx *xran_ctx = xran_dev_get_ctx();
const struct xran_fh_init *fh_init = &xran_ctx->fh_init;
int nPRBs = xran_ctx->fh_cfg.nULRBs;
int fftsize = 1 << xran_ctx->fh_cfg.ru_conf.fftSize;
int slot_offset_rxdata = 3 & (*slot);
uint32_t slot_size = 4 * 14 * 4096;
uint8_t *rx_data = (uint8_t *)ru->rxdataF[0];
uint8_t *start_ptr = NULL;
int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports;
for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet.
for (uint8_t ant_id = 0; ant_id < ru->nb_rx; ant_id++) {
rx_data = (uint8_t *)ru->rxdataF[ant_id];
start_ptr = rx_data + (slot_size * slot_offset_rxdata);
xran_ctx = xran_dev_get_ctx_by_id(ant_id / nb_rx_per_ru);
const struct xran_fh_config *fh_config = &xran_ctx->fh_cfg;
int tdd_period = fh_config->frame_conf.nTddPeriod;
int slot_in_period = *slot % tdd_period;
if (fh_config->frame_conf.sSlotConfig[slot_in_period].nSymbolType[XRAN_NUM_OF_SYMBOL_PER_SLOT - 1] == 0)
continue;
// skip processing this slot if the last symbol in the slot is TX
// (no RX in this slot)
// This loop would better be more inner to avoid confusion and maybe also errors.
for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) {
/* the callback is for mixed and UL slots. In mixed, we have to
* skip DL and guard symbols. */
if (fh_config->frame_conf.sSlotConfig[slot_in_period].nSymbolType[sym_idx] != 1 /* UL */)
continue;
uint8_t *pData;
uint8_t *pPrbMapData = xran_ctx->sFrontHaulRxPrbMapBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_rx_per_ru]
.sBufferList.pBuffers->pData;
struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData;
struct xran_prb_elm *pRbElm = &pPrbMap->prbMap[0];
struct xran_section_desc *p_sec_desc = pRbElm->p_sec_desc[sym_idx][0];
uint32_t one_rb_size =
(((pRbElm->iqWidth == 0) || (pRbElm->iqWidth == 16)) ? (N_SC_PER_PRB * 2 * 2) : (3 * pRbElm->iqWidth + 1));
if (fh_init->mtu < pRbElm->nRBSize * one_rb_size)
pData = xran_ctx->sFrontHaulRxBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_rx_per_ru]
.sBufferList.pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT]
.pData;
else
pData = p_sec_desc->pData;
ptr = pData;
pos = (int32_t *)(start_ptr + (4 * sym_idx * 4096));
uint8_t *u8dptr;
struct xran_prb_map *pRbMap = pPrbMap;
AssertFatal(ptr != NULL, "ptr NULL\n");
AssertFatal(pos != NULL, "pos NULL\n");
if (1) {
uint32_t idxElm = 0;
u8dptr = (uint8_t *)ptr;
int16_t payload_len = 0;
uint8_t *src = (uint8_t *)u8dptr;
LOG_D(PHY, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm);
for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) {
LOG_D(PHY,
"prbMap[%d] : PRBstart %d nPRBs %d\n",
idxElm,
pRbMap->prbMap[idxElm].nRBStart,
pRbMap->prbMap[idxElm].nRBSize);
pRbElm = &pRbMap->prbMap[idxElm];
int pos_len = 0;
int neg_len = 0;
if (pRbElm->nRBStart < (nPRBs >> 1)) // there are PRBs left of DC
neg_len = min((nPRBs * 6) - (pRbElm->nRBStart * 12), pRbElm->nRBSize * N_SC_PER_PRB);
pos_len = (pRbElm->nRBSize * N_SC_PER_PRB) - neg_len;
src = pData;
// Calculation of the pointer for the section in the buffer.
// positive half
uint8_t *dst1 = (uint8_t *)(pos + (neg_len == 0 ? ((pRbElm->nRBStart * N_SC_PER_PRB) - (nPRBs * 6)) : 0));
// negative half
uint8_t *dst2 = (uint8_t *)(pos + (pRbElm->nRBStart * N_SC_PER_PRB) + fftsize - (nPRBs * 6));
int32_t local_dst[pRbElm->nRBSize * N_SC_PER_PRB] __attribute__((aligned(64)));
if (pRbElm->compMethod == XRAN_COMPMETHOD_NONE) {
// NOTE: gcc 11 knows how to generate AVX2 for this!
for (idx = 0; idx < pRbElm->nRBSize * N_SC_PER_PRB * 2; idx++)
((int16_t *)local_dst)[idx] = ((int16_t)ntohs(((uint16_t *)src)[idx])) >> 2;
memcpy((void *)dst2, (void *)local_dst, neg_len * 4);
memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4);
} else if (pRbElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) {
struct xranlib_decompress_request bfp_decom_req;
struct xranlib_decompress_response bfp_decom_rsp;
payload_len = (3 * pRbElm->iqWidth + 1) * pRbElm->nRBSize;
memset(&bfp_decom_req, 0, sizeof(struct xranlib_decompress_request));
memset(&bfp_decom_rsp, 0, sizeof(struct xranlib_decompress_response));
bfp_decom_req.data_in = (int8_t *)src;
bfp_decom_req.numRBs = pRbElm->nRBSize;
bfp_decom_req.len = payload_len;
bfp_decom_req.compMethod = pRbElm->compMethod;
bfp_decom_req.iqWidth = pRbElm->iqWidth;
bfp_decom_rsp.data_out = (int16_t *)local_dst;
bfp_decom_rsp.len = 0;
xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp);
memcpy((void *)dst2, (void *)local_dst, neg_len * 4);
memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4);
outcnt++;
} else {
printf("pRbElm->compMethod == %d is not supported\n", pRbElm->compMethod);
exit(-1);
}
}
} else {
return 0;
}
} // sym_ind
} // ant_ind
} // vv_inf
if ((*frame & 0x7f) == 0 && *slot == 0 && xran_get_common_counters(gxran_handle, &x_counters[0]) == XRAN_STATUS_SUCCESS) {
for (int o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
LOG_I(NR_PHY,
"[%s%d][rx %7ld pps %7ld kbps %7ld][tx %7ld pps %7ld kbps %7ld][Total Msgs_Rcvd %ld]\n",
"o-du ",
o_xu_id,
x_counters[o_xu_id].rx_counter,
x_counters[o_xu_id].rx_counter - old_rx_counter[o_xu_id],
x_counters[o_xu_id].rx_bytes_per_sec * 8 / 1000L,
x_counters[o_xu_id].tx_counter,
x_counters[o_xu_id].tx_counter - old_tx_counter[o_xu_id],
x_counters[o_xu_id].tx_bytes_per_sec * 8 / 1000L,
x_counters[o_xu_id].Total_msgs_rcvd);
for (int rxant = 0; rxant < ru->nb_rx / fh_init->xran_ports; rxant++)
LOG_I(NR_PHY,
"[%s%d][pusch%d %7ld prach%d %7ld]\n",
"o_du",
o_xu_id,
rxant,
x_counters[o_xu_id].rx_pusch_packets[rxant],
rxant,
x_counters[o_xu_id].rx_prach_packets[rxant]);
if (x_counters[o_xu_id].rx_counter > old_rx_counter[o_xu_id])
old_rx_counter[o_xu_id] = x_counters[o_xu_id].rx_counter;
if (x_counters[o_xu_id].tx_counter > old_tx_counter[o_xu_id])
old_tx_counter[o_xu_id] = x_counters[o_xu_id].tx_counter;
}
}
return (0);
}
int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp)
{
int tti = /*frame*SUBFRAMES_PER_SYSTEMFRAME*SLOTNUM_PER_SUBFRAME+*/ 20 * frame
+ slot; // commented out temporarily to check that compilation of oran 5g is working.
void *ptr = NULL;
int32_t *pos = NULL;
int idx = 0;
struct xran_device_ctx *xran_ctx = xran_dev_get_ctx();
const struct xran_fh_init *fh_init = &xran_ctx->fh_init;
int nPRBs = xran_ctx->fh_cfg.nDLRBs;
int fftsize = 1 << xran_ctx->fh_cfg.ru_conf.fftSize;
int nb_tx_per_ru = ru->nb_tx / fh_init->xran_ports;
for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet.
for (uint8_t ant_id = 0; ant_id < ru->nb_tx; ant_id++) {
xran_ctx = xran_dev_get_ctx_by_id(ant_id / nb_tx_per_ru);
// This loop would better be more inner to avoid confusion and maybe also errors.
for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) {
uint8_t *pData = xran_ctx->sFrontHaulTxBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_tx_per_ru]
.sBufferList.pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT]
.pData;
uint8_t *pPrbMapData = xran_ctx->sFrontHaulTxPrbMapBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_tx_per_ru]
.sBufferList.pBuffers->pData;
struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData;
ptr = pData;
pos =
&ru->txdataF_BF[ant_id][sym_idx * 4096 /*fp->ofdm_symbol_size*/]; // We had to use a different ru structure than benetel
// so the access to the buffer is not the same.
uint8_t *u8dptr;
struct xran_prb_map *pRbMap = pPrbMap;
int32_t sym_id = sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT;
if (ptr && pos) {
uint32_t idxElm = 0;
u8dptr = (uint8_t *)ptr;
int16_t payload_len = 0;
uint8_t *dst = (uint8_t *)u8dptr;
struct xran_prb_elm *p_prbMapElm = &pRbMap->prbMap[idxElm];
for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) {
struct xran_section_desc *p_sec_desc = NULL;
p_prbMapElm = &pRbMap->prbMap[idxElm];
p_sec_desc =
// assumes one fragment per symbol
p_prbMapElm->p_sec_desc[sym_id][0];
dst = xran_add_hdr_offset(dst, p_prbMapElm->compMethod);
if (p_sec_desc == NULL) {
printf("p_sec_desc == NULL\n");
exit(-1);
}
uint16_t *dst16 = (uint16_t *)dst;
int pos_len = 0;
int neg_len = 0;
if (p_prbMapElm->nRBStart < (nPRBs >> 1)) // there are PRBs left of DC
neg_len = min((nPRBs * 6) - (p_prbMapElm->nRBStart * 12), p_prbMapElm->nRBSize * N_SC_PER_PRB);
pos_len = (p_prbMapElm->nRBSize * N_SC_PER_PRB) - neg_len;
// Calculation of the pointer for the section in the buffer.
// start of positive frequency component
uint16_t *src1 = (uint16_t *)&pos[(neg_len == 0) ? ((p_prbMapElm->nRBStart * N_SC_PER_PRB) - (nPRBs * 6)) : 0];
// start of negative frequency component
uint16_t *src2 = (uint16_t *)&pos[(p_prbMapElm->nRBStart * N_SC_PER_PRB) + fftsize - (nPRBs * 6)];
uint32_t local_src[p_prbMapElm->nRBSize * N_SC_PER_PRB] __attribute__((aligned(64)));
memcpy((void *)local_src, (void *)src2, neg_len * 4);
memcpy((void *)&local_src[neg_len], (void *)src1, pos_len * 4);
if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_NONE) {
payload_len = p_prbMapElm->nRBSize * N_SC_PER_PRB * 4L;
/* convert to Network order */
// NOTE: ggc 11 knows how to generate AVX2 for this!
for (idx = 0; idx < (pos_len + neg_len) * 2; idx++)
((uint16_t *)dst16)[idx] = htons(((uint16_t *)local_src)[idx]);
} else if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) {
struct xranlib_compress_request bfp_com_req;
struct xranlib_compress_response bfp_com_rsp;
payload_len = (3 * p_prbMapElm->iqWidth + 1) * p_prbMapElm->nRBSize;
memset(&bfp_com_req, 0, sizeof(struct xranlib_compress_request));
memset(&bfp_com_rsp, 0, sizeof(struct xranlib_compress_response));
bfp_com_req.data_in = (int16_t *)local_src;
bfp_com_req.numRBs = p_prbMapElm->nRBSize;
bfp_com_req.len = payload_len;
bfp_com_req.compMethod = p_prbMapElm->compMethod;
bfp_com_req.iqWidth = p_prbMapElm->iqWidth;
bfp_com_rsp.data_out = (int8_t *)dst;
bfp_com_rsp.len = 0;
xranlib_compress_avx512(&bfp_com_req, &bfp_com_rsp);
} else {
printf("p_prbMapElm->compMethod == %d is not supported\n", p_prbMapElm->compMethod);
exit(-1);
}
p_sec_desc->iq_buffer_offset = RTE_PTR_DIFF(dst, u8dptr);
p_sec_desc->iq_buffer_len = payload_len;
dst += payload_len;
dst = xran_add_hdr_offset(dst, p_prbMapElm->compMethod);
}
// The tti should be updated as it increased.
pRbMap->tti_id = tti;
} else {
printf("ptr ==NULL\n");
exit(-1); // fails here??
}
}
}
}
return (0);
}
+37
View File
@@ -0,0 +1,37 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef OAIORAN_H
#define OAIORAN_H
#include <stdint.h>
#include "xran_fh_o_du.h"
typedef struct {
uint32_t tti;
uint32_t sl;
uint32_t f;
} oran_sync_info_t;
void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status);
int oai_physide_dl_tti_call_back(void *param);
#endif /* OAIORAN_H */
+886
View File
@@ -0,0 +1,886 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "oran-config.h"
#include "oran-params.h"
#include "common/utils/assertions.h"
#include "common_lib.h"
#include "xran_fh_o_du.h"
#include "xran_cp_api.h"
#include "rte_ether.h"
#include "stdio.h"
#include "string.h"
static void print_fh_eowd_cmn(unsigned index, const struct xran_ecpri_del_meas_cmn *eowd_cmn)
{
printf("\
eowd_cmn[%d]:\n\
initiator_en %d\n\
numberOfSamples %d\n\
filterType %d\n\
responseTo %ld\n\
measVf %d\n\
measState %d\n\
measId %d\n\
measMethod %d\n\
owdm_enable %d\n\
owdm_PlLength %d\n",
index,
eowd_cmn->initiator_en,
eowd_cmn->numberOfSamples,
eowd_cmn->filterType,
eowd_cmn->responseTo,
eowd_cmn->measVf,
eowd_cmn->measState,
eowd_cmn->measId,
eowd_cmn->measMethod,
eowd_cmn->owdm_enable,
eowd_cmn->owdm_PlLength);
}
static void print_fh_eowd_port(unsigned index, unsigned vf, const struct xran_ecpri_del_meas_port *eowd_port)
{
printf("\
eowd_port[%d][%d]:\n\
t1 %ld\n\
t2 %ld\n\
tr %ld\n\
delta %ld\n\
portid %d\n\
runMeas %d\n\
currentMeasID %d\n\
msState %d\n\
numMeas %d\n\
txDone %d\n\
rspTimerIdx %ld\n\
delaySamples [%ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld]\n\
delayAvg %ld\n",
index,
vf,
eowd_port->t1,
eowd_port->t2,
eowd_port->tr,
eowd_port->delta,
eowd_port->portid,
eowd_port->runMeas,
eowd_port->currentMeasID,
eowd_port->msState,
eowd_port->numMeas,
eowd_port->txDone,
eowd_port->rspTimerIdx,
eowd_port->delaySamples[0],
eowd_port->delaySamples[1],
eowd_port->delaySamples[2],
eowd_port->delaySamples[3],
eowd_port->delaySamples[4],
eowd_port->delaySamples[5],
eowd_port->delaySamples[6],
eowd_port->delaySamples[7],
eowd_port->delaySamples[8],
eowd_port->delaySamples[9],
eowd_port->delaySamples[10],
eowd_port->delaySamples[11],
eowd_port->delaySamples[12],
eowd_port->delaySamples[13],
eowd_port->delaySamples[14],
eowd_port->delaySamples[15],
eowd_port->delayAvg);
}
static void print_fh_init_io_cfg(const struct xran_io_cfg *io_cfg)
{
printf("\
io_cfg:\n\
id %d (%s)\n\
num_vfs %d\n\
num_rxq %d\n\
dpdk_dev [%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s]\n\
bbdev_dev %s\n\
bbdev_mode %d\n\
dpdkIoVaMode %d\n\
dpdkMemorySize %d\n",
io_cfg->id,
io_cfg->id == 0 ? "O-DU" : "O-RU",
io_cfg->num_vfs,
io_cfg->num_rxq,
io_cfg->dpdk_dev[XRAN_UP_VF],
io_cfg->dpdk_dev[XRAN_CP_VF],
io_cfg->dpdk_dev[XRAN_UP_VF1],
io_cfg->dpdk_dev[XRAN_CP_VF1],
io_cfg->dpdk_dev[XRAN_UP_VF2],
io_cfg->dpdk_dev[XRAN_CP_VF2],
io_cfg->dpdk_dev[XRAN_UP_VF3],
io_cfg->dpdk_dev[XRAN_CP_VF3],
io_cfg->dpdk_dev[XRAN_UP_VF4],
io_cfg->dpdk_dev[XRAN_CP_VF4],
io_cfg->dpdk_dev[XRAN_UP_VF5],
io_cfg->dpdk_dev[XRAN_CP_VF5],
io_cfg->dpdk_dev[XRAN_UP_VF6],
io_cfg->dpdk_dev[XRAN_CP_VF6],
io_cfg->dpdk_dev[XRAN_UP_VF7],
io_cfg->dpdk_dev[XRAN_CP_VF7],
io_cfg->bbdev_dev[0],
io_cfg->bbdev_mode,
io_cfg->dpdkIoVaMode,
io_cfg->dpdkMemorySize);
printf("\
core %d\n\
system_core %d\n\
pkt_proc_core %016lx\n\
pkt_proc_core_64_127 %016lx\n\
pkt_aux_core %d\n\
timing_core %d\n\
port [%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, ]\n\
io_sleep %d\n\
nEthLinePerPort %d\n\
nEthLineSpeed %d\n\
one_vf_cu_plane %d\n",
io_cfg->core,
io_cfg->system_core,
io_cfg->pkt_proc_core,
io_cfg->pkt_proc_core_64_127,
io_cfg->pkt_aux_core,
io_cfg->timing_core,
io_cfg->port[XRAN_UP_VF],
io_cfg->port[XRAN_CP_VF],
io_cfg->port[XRAN_UP_VF1],
io_cfg->port[XRAN_CP_VF1],
io_cfg->port[XRAN_UP_VF2],
io_cfg->port[XRAN_CP_VF2],
io_cfg->port[XRAN_UP_VF3],
io_cfg->port[XRAN_CP_VF3],
io_cfg->port[XRAN_UP_VF4],
io_cfg->port[XRAN_CP_VF4],
io_cfg->port[XRAN_UP_VF5],
io_cfg->port[XRAN_CP_VF5],
io_cfg->port[XRAN_UP_VF6],
io_cfg->port[XRAN_CP_VF6],
io_cfg->port[XRAN_UP_VF7],
io_cfg->port[XRAN_CP_VF7],
io_cfg->io_sleep,
io_cfg->nEthLinePerPort,
io_cfg->nEthLineSpeed,
io_cfg->one_vf_cu_plane);
print_fh_eowd_cmn(0, &io_cfg->eowd_cmn[0]);
print_fh_eowd_cmn(1, &io_cfg->eowd_cmn[1]);
for (int i = 0; i < 2; ++i)
for (int v = 0; v < io_cfg->num_vfs; ++v)
print_fh_eowd_port(i, v, &io_cfg->eowd_port[i][v]);
}
static void print_fh_init_eaxcid_conf(const struct xran_eaxcid_config *eaxcid_conf)
{
printf("\
eAxCId_conf:\n\
mask_cuPortId 0x%04x\n\
mask_bandSectorId 0x%04x\n\
mask_ccId 0x%04x\n\
mask_ruPortId 0x%04x\n\
bit_cuPortId %d\n\
bit_bandSectorId %d\n\
bit_ccId %d\n\
bit_ruPortId %d\n",
eaxcid_conf->mask_cuPortId,
eaxcid_conf->mask_bandSectorId,
eaxcid_conf->mask_ccId,
eaxcid_conf->mask_ruPortId,
eaxcid_conf->bit_cuPortId,
eaxcid_conf->bit_bandSectorId,
eaxcid_conf->bit_ccId,
eaxcid_conf->bit_ruPortId);
}
static void print_ether_addr(const char *pre, int num_ether, const struct rte_ether_addr *addrs)
{
printf("%s [", pre);
for (int i = 0; i < num_ether; ++i) {
char buf[18];
rte_ether_format_addr(buf, 18, &addrs[i]);
printf("%s", buf);
if (i != num_ether - 1)
printf(", ");
}
printf("]\n");
}
void print_fh_init(const struct xran_fh_init *fh_init)
{
printf("xran_fh_init:\n");
print_fh_init_io_cfg(&fh_init->io_cfg);
print_fh_init_eaxcid_conf(&fh_init->eAxCId_conf);
printf("\
xran_ports %d\n\
dpdkBasebandFecMode %d\n\
dpdkBasebandDevice %s\n\
filePrefix %s\n\
mtu %d\n",
fh_init->xran_ports,
fh_init->dpdkBasebandFecMode,
fh_init->dpdkBasebandDevice,
fh_init->filePrefix,
fh_init->mtu);
print_ether_addr(" p_o_du_addr", fh_init->xran_ports * fh_init->io_cfg.num_vfs, (struct rte_ether_addr *)fh_init->p_o_du_addr);
print_ether_addr(" p_o_ru_addr", fh_init->xran_ports * fh_init->io_cfg.num_vfs, (struct rte_ether_addr *)fh_init->p_o_ru_addr);
printf("\
totalBfWeights %d\n",
fh_init->totalBfWeights);
}
static void print_prach_config(const struct xran_prach_config *prach_conf)
{
printf("\
prach_config:\n\
nPrachConfIdx %d\n\
nPrachSubcSpacing %d\n\
nPrachZeroCorrConf %d\n\
nPrachRestrictSet %d\n\
nPrachRootSeqIdx %d\n\
nPrachFreqStart %d\n\
nPrachFreqOffset %d\n\
nPrachFilterIdx %d\n\
startSymId %d\n\
lastSymId %d\n\
startPrbc %d\n\
numPrbc %d\n\
timeOffset %d\n\
freqOffset %d\n\
eAxC_offset %d\n",
prach_conf->nPrachConfIdx,
prach_conf->nPrachSubcSpacing,
prach_conf->nPrachZeroCorrConf,
prach_conf->nPrachRestrictSet,
prach_conf->nPrachRootSeqIdx,
prach_conf->nPrachFreqStart,
prach_conf->nPrachFreqOffset,
prach_conf->nPrachFilterIdx,
prach_conf->startSymId,
prach_conf->lastSymId,
prach_conf->startPrbc,
prach_conf->numPrbc,
prach_conf->timeOffset,
prach_conf->freqOffset,
prach_conf->eAxC_offset);
}
static void print_srs_config(const struct xran_srs_config *srs_conf)
{
printf("\
srs_config:\n\
symbMask %04x\n\
eAxC_offset %d\n",
srs_conf->symbMask,
srs_conf->eAxC_offset);
}
static void print_frame_config(const struct xran_frame_config *frame_conf)
{
printf("\
frame_conf:\n\
nFrameDuplexType %s\n\
nNumerology %d\n\
nTddPeriod %d\n",
frame_conf->nFrameDuplexType == XRAN_TDD ? "TDD" : "FDD",
frame_conf->nNumerology,
frame_conf->nTddPeriod);
for (int i = 0; i < frame_conf->nTddPeriod; ++i) {
printf(" sSlotConfig[%d]: ", i);
for (int s = 0; s < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++s) {
uint8_t nSymbolType = frame_conf->sSlotConfig[i].nSymbolType[s];
printf("%c", nSymbolType == 0 ? 'D' : (nSymbolType == 1 ? 'U' : 'G'));
}
printf("\n");
}
}
static void print_ru_config(const struct xran_ru_config *ru_conf)
{
printf("\
ru_config:\n\
xranTech %s\n\
xranCat %s\n\
xranCompHdrType %s\n\
iqWidth %d\n\
compMeth %d\n\
iqWidth_PRACH %d\n\
compMeth_PRACH %d\n\
fftSize %d\n\
byteOrder %s\n\
iqOrder %s\n\
xran_max_frame %d\n",
ru_conf->xranTech == XRAN_RAN_5GNR ? "NR" : "LTE",
ru_conf->xranCat == XRAN_CATEGORY_A ? "A" : "B",
ru_conf->xranCompHdrType == XRAN_COMP_HDR_TYPE_DYNAMIC ? "dynamic" : "static",
ru_conf->iqWidth,
ru_conf->compMeth,
ru_conf->iqWidth_PRACH,
ru_conf->compMeth_PRACH,
ru_conf->fftSize,
ru_conf->byteOrder == XRAN_NE_BE_BYTE_ORDER ? "network/BE" : "CPU/LE",
ru_conf->iqOrder == XRAN_I_Q_ORDER ? "I_Q" : "Q_I",
ru_conf->xran_max_frame);
}
void print_fh_config(const struct xran_fh_config *fh_config)
{
printf("xran_fh_config:\n");
printf("\
dpdk_port %d\n\
sector_id %d\n\
nCC %d\n\
neAxc %d\n\
neAxcUl %d\n\
nAntElmTRx %d\n\
nDLFftSize %d\n\
nULFftSize %d\n\
nDLRBs %d\n\
nULRBs %d\n\
nDLAbsFrePointA %d\n\
nULAbsFrePointA %d\n\
nDLCenterFreqARFCN %d\n\
nULCenterFreqARFCN %d\n\
ttiCb %p\n\
ttiCbParam %p\n",
fh_config->dpdk_port,
fh_config->sector_id,
fh_config->nCC,
fh_config->neAxc,
fh_config->neAxcUl,
fh_config->nAntElmTRx,
fh_config->nDLFftSize,
fh_config->nULFftSize,
fh_config->nDLRBs,
fh_config->nULRBs,
fh_config->nDLAbsFrePointA,
fh_config->nULAbsFrePointA,
fh_config->nDLCenterFreqARFCN,
fh_config->nULCenterFreqARFCN,
fh_config->ttiCb,
fh_config->ttiCbParam);
printf("\
Tadv_cp_dl %d\n\
T2a_min_cp_dl %d\n\
T2a_max_cp_dl %d\n\
T2a_min_cp_ul %d\n\
T2a_max_cp_ul %d\n\
T2a_min_up %d\n\
T2a_max_up %d\n\
Ta3_min %d\n\
Ta3_max %d\n\
T1a_min_cp_dl %d\n\
T1a_max_cp_dl %d\n\
T1a_min_cp_ul %d\n\
T1a_max_cp_ul %d\n\
T1a_min_up %d\n\
T1a_max_up %d\n\
Ta4_min %d\n\
Ta4_max %d\n",
fh_config->Tadv_cp_dl,
fh_config->T2a_min_cp_dl,
fh_config->T2a_max_cp_dl,
fh_config->T2a_min_cp_ul,
fh_config->T2a_max_cp_ul,
fh_config->T2a_min_up,
fh_config->T2a_max_up,
fh_config->Ta3_min,
fh_config->Ta3_max,
fh_config->T1a_min_cp_dl,
fh_config->T1a_max_cp_dl,
fh_config->T1a_min_cp_ul,
fh_config->T1a_max_cp_ul,
fh_config->T1a_min_up,
fh_config->T1a_max_up,
fh_config->Ta4_min,
fh_config->Ta4_max);
printf("\
enableCP %d\n\
prachEnable %d\n\
srsEnable %d\n\
puschMaskEnable %d\n\
puschMaskSlot %d\n\
cp_vlan_tag %d\n\
up_vlan_tag %d\n\
debugStop %d\n\
debugStopCount %d\n\
DynamicSectionEna %d\n\
GPS_Alpha %d\n\
GPS_Beta %d\n",
fh_config->enableCP,
fh_config->prachEnable,
fh_config->srsEnable,
fh_config->puschMaskEnable,
fh_config->puschMaskSlot,
fh_config->cp_vlan_tag,
fh_config->up_vlan_tag,
fh_config->debugStop,
fh_config->debugStopCount,
fh_config->DynamicSectionEna,
fh_config->GPS_Alpha,
fh_config->GPS_Beta);
print_prach_config(&fh_config->prach_conf);
print_srs_config(&fh_config->srs_conf);
print_frame_config(&fh_config->frame_conf);
print_ru_config(&fh_config->ru_conf);
printf("\
bbdev_enc %p\n\
bbdev_dec %p\n\
tx_cp_eAxC2Vf [not implemented by fhi_lib]\n\
tx_up_eAxC2Vf [not implemented by fhi_lib]\n\
rx_cp_eAxC2Vf [not implemented by fhi_lib]\n\
rx_up_eAxC2Vf [not implemented by fhi_lib]\n\
log_level %d\n\
max_sections_per_slot %d\n\
max_sections_per_symbol %d\n",
fh_config->bbdev_enc,
fh_config->bbdev_dec,
fh_config->log_level,
fh_config->max_sections_per_slot,
fh_config->max_sections_per_symbol);
}
static const paramdef_t *gpd(const paramdef_t *pd, int num, const char *name)
{
/* the config module does not know const-correctness... */
int idx = config_paramidx_fromname((paramdef_t *)pd, num, (char *)name);
DevAssert(idx >= 0);
return &pd[idx];
}
static uint64_t get_u64_mask(const paramdef_t *pd)
{
DevAssert(pd != NULL);
AssertFatal(pd->numelt > 0, "no entries for creation of mask\n");
uint64_t mask = 0;
for (int i = 0; i < pd->numelt; ++i) {
int num = pd->iptr[i];
AssertFatal(num >= 0 && num < 64, "cannot put element of %d in 64-bit mask\n", num);
mask |= 1 << num;
}
return mask;
}
static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, int nump)
{
DevAssert(fhip != NULL);
int num_dev = gpd(fhip, nump, ORAN_CONFIG_DPDK_DEVICES)->numelt;
AssertFatal(num_dev > 0, "need to provide DPDK devices for O-RAN 7.2 Fronthaul\n");
AssertFatal(num_dev < 17, "too many DPDK devices for O-RAN 7.2 Fronthaul\n");
io_cfg->id = 0; // 0 = O-DU
io_cfg->num_vfs = num_dev;
io_cfg->num_rxq = 2; // Assume two HW RX queues per RU
for (int i = 0; i < num_dev; ++i)
io_cfg->dpdk_dev[i] = strdup(gpd(fhip, nump, ORAN_CONFIG_DPDK_DEVICES)->strlistptr[i]);
//io_cfg->bbdev_dev = NULL;
io_cfg->bbdev_mode = XRAN_BBDEV_NOT_USED; // none
io_cfg->dpdkIoVaMode = 0; /* IOVA mode */
io_cfg->dpdkMemorySize = 0; /* DPDK memory size */
io_cfg->core = *gpd(fhip, nump, ORAN_CONFIG_IO_CORE)->iptr;
io_cfg->system_core = 0; /* TODO how called in sample app? */
io_cfg->pkt_proc_core = get_u64_mask(gpd(fhip, nump, ORAN_CONFIG_WORKER_CORES));
io_cfg->pkt_proc_core_64_127 = 0x0; // bitmap 0 -> no core
io_cfg->pkt_aux_core = 0; /* sapmle app says 0 = "do not start" */
io_cfg->timing_core = *gpd(fhip, nump, ORAN_CONFIG_IO_CORE)->iptr; /* sample app: equal to io_core */
//io_cfg->port = {0}; // all 0
io_cfg->io_sleep = 0; // no sleep
io_cfg->nEthLinePerPort = *gpd(fhip, nump, ORAN_CONFIG_NETHPERPORT)->uptr;
io_cfg->nEthLineSpeed = *gpd(fhip, nump, ORAN_CONFIG_NETHSPEED)->uptr;
io_cfg->one_vf_cu_plane = 0; // false: C/U-plane don't share VF
// io_cfg->eowd_cmn[0] // all 0
// io_cfg->eowd_cmn[1] // all 0
// io_cfg->eowd_port[0]... // all 0
return true;
}
static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat)
{
// values taken from sample app
switch (cat) {
case XRAN_CATEGORY_A:
eaxcid_conf->mask_cuPortId = 0xf000;
eaxcid_conf->mask_bandSectorId = 0x0f00;
eaxcid_conf->mask_ccId = 0x00f0;
eaxcid_conf->mask_ruPortId = 0x000f;
eaxcid_conf->bit_cuPortId = 12;
eaxcid_conf->bit_bandSectorId = 8;
eaxcid_conf->bit_ccId = 4;
eaxcid_conf->bit_ruPortId = 0;
break;
case XRAN_CATEGORY_B:
eaxcid_conf->mask_cuPortId = 0xf000;
eaxcid_conf->mask_bandSectorId = 0x0c00;
eaxcid_conf->mask_ccId = 0x0300;
eaxcid_conf->mask_ruPortId = 0x000f;
eaxcid_conf->bit_cuPortId = 12;
eaxcid_conf->bit_bandSectorId = 10;
eaxcid_conf->bit_ccId = 8;
eaxcid_conf->bit_ruPortId = 0;
break;
default:
return false;
}
return true;
}
uint8_t *get_ether_addr(const char *addr, struct rte_ether_addr *ether_addr)
{
#pragma GCC diagnostic push
// the following line disables the deprecated warning
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
int ret = rte_ether_unformat_addr(addr, ether_addr);
#pragma GCC diagnostic pop
if (ret == 0)
return (uint8_t *)ether_addr;
return NULL;
}
bool set_fh_init(struct xran_fh_init *fh_init)
{
memset(fh_init, 0, sizeof(*fh_init));
// verify oran section is present: we don't have a list but the below returns
// numelt > 0 if the block is there
paramlist_def_t pl = {0};
strncpy(pl.listname, CONFIG_STRING_ORAN, sizeof(pl.listname) - 1);
config_getlist(config_get_if(), &pl, NULL, 0, /* prefix */ NULL);
if (pl.numelt == 0) {
printf("Configuration section \"%s\" not present: cannot initialize fhi_lib!\n", CONFIG_STRING_ORAN);
return false;
}
paramdef_t fhip[] = ORAN_GLOBALPARAMS_DESC;
int nump = sizeofArray(fhip);
int ret = config_get(config_get_if(), fhip, nump, CONFIG_STRING_ORAN);
if (ret <= 0) {
printf("problem reading section \"%s\"\n", CONFIG_STRING_ORAN);
return false;
}
paramdef_t FHconfigs[] = ORAN_FH_DESC;
paramlist_def_t FH_ConfigList = {CONFIG_STRING_ORAN_FH};
char aprefix[MAX_OPTNAME_SIZE] = {0};
sprintf(aprefix, "%s", CONFIG_STRING_ORAN);
const int nfh = sizeofArray(FHconfigs);
config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix);
int num_rus = FH_ConfigList.numelt;
int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt;
int num_du_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt;
int num_vfs = gpd(fhip, nump, ORAN_CONFIG_DPDK_DEVICES)->numelt;
if (num_ru_addr != num_du_addr) {
printf("need to have same number of DUs and RUs!\n");
return false;
}
if (num_ru_addr != num_vfs) {
printf("need to have as many RU/DU entries as DPDK devices (one VF for CP and UP each)\n");
return false;
}
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump))
return false;
if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, XRAN_CATEGORY_A))
return false;
fh_init->xran_ports = num_rus;
fh_init->dpdkBasebandFecMode = 0;
fh_init->dpdkBasebandDevice = NULL;
fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr); // see DPDK --file-prefix
fh_init->mtu = *gpd(fhip, nump, ORAN_CONFIG_MTU)->uptr;
// if multiple RUs: xran_ethdi_init_dpdk_io() iterates over
// &p_o_ru_addr[i]
char **du_addrs = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr;
fh_init->p_o_du_addr = calloc(num_du_addr, sizeof(struct rte_ether_addr));
AssertFatal(fh_init->p_o_du_addr != NULL, "out of memory\n");
for (int i = 0; i < num_du_addr; ++i) {
struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_du_addr;
if (get_ether_addr(du_addrs[i], &ea[i]) == NULL) {
printf("could not read ethernet address '%s' for DU!\n", du_addrs[i]);
return false;
}
}
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr;
AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n");
for (int i = 0; i < num_ru_addr; ++i) {
struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr;
if (get_ether_addr(ru_addrs[i], &ea[i]) == NULL) {
printf("could not read ethernet address '%s' for RU!\n", ru_addrs[i]);
return false;
}
}
fh_init->totalBfWeights = 32;
return true;
}
static enum xran_cp_filterindex get_prach_filterindex_fr1(duplex_mode_t mode, int prach_index)
{
if (mode == duplex_mode_TDD) {
// 38.211 table 6.3.3.2-3 "unpaired spectrum" -> TDD
switch (prach_index) {
case 0 ... 39:
case 256 ... 262:
return XRAN_FILTERINDEX_PRACH_012;
case 40 ... 66:
return XRAN_FILTERINDEX_PRACH_3;
case 67 ... 255:
return XRAN_FILTERINDEX_PRACH_ABC;
}
} else if (mode == duplex_mode_FDD) {
// 38.211 table 6.3.3.2-2 "paired spectrum" -> FDD
switch (prach_index) {
case 0 ... 59:
return XRAN_FILTERINDEX_PRACH_012;
case 60 ... 86:
return XRAN_FILTERINDEX_PRACH_3;
case 87 ... 255:
return XRAN_FILTERINDEX_PRACH_ABC;
default:
AssertFatal(false, "unknown PRACH index %d\n", prach_index);
}
} else {
AssertFatal(false, "unsupported duplex mode %d\n", mode);
}
return XRAN_FILTERINDEX_STANDARD;
}
// PRACH guard interval. Raymond: "[it] is not in the configuration, (i.e. it
// is deterministic depending on others). LiteON must hard-code this in the
// O-RU itself, benetel doesn't (as O-RAN specifies). So we will need to tell
// the driver what the case is and provide"
// this is a hack
int g_kbar;
static bool set_fh_prach_config(const openair0_config_t *oai0,
const paramdef_t *prachp,
int nprach,
struct xran_prach_config *prach_config)
{
const split7_config_t *s7cfg = &oai0->split7;
// for FR2, need at least to update nPrachFilterIdx
AssertFatal(oai0->nr_band < 100, "can only handle FR1!\n");
prach_config->nPrachConfIdx = s7cfg->prach_index;
prach_config->nPrachSubcSpacing = oai0->nr_scs_for_raster;
prach_config->nPrachZeroCorrConf = 0;
prach_config->nPrachRestrictSet = 0;
prach_config->nPrachRootSeqIdx = 0;
prach_config->nPrachFreqStart = s7cfg->prach_freq_start;
prach_config->nPrachFreqOffset = (s7cfg->prach_freq_start * 12 - oai0->num_rb_dl * 6) * 2;
prach_config->nPrachFilterIdx = get_prach_filterindex_fr1(oai0->duplex_mode, s7cfg->prach_index);
prach_config->startSymId = 0;
prach_config->lastSymId = 0;
prach_config->startPrbc = 0;
prach_config->numPrbc = 0;
prach_config->timeOffset = 0;
prach_config->freqOffset = 0;
prach_config->eAxC_offset = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_EAXC_OFFSET)->u8ptr;
g_kbar = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_KBAR)->uptr;
return true;
}
static bool set_fh_srs_config(struct xran_srs_config *srs_config)
{
srs_config->symbMask = 0;
srs_config->eAxC_offset = 8;
return true;
}
static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame_config *frame_config)
{
const split7_config_t *s7cfg = &oai0->split7;
frame_config->nFrameDuplexType = oai0->duplex_mode == duplex_mode_TDD ? XRAN_TDD : XRAN_FDD;
frame_config->nNumerology = oai0->nr_scs_for_raster;
frame_config->nTddPeriod = s7cfg->n_tdd_period;
struct xran_slot_config *sc = &frame_config->sSlotConfig[0];
for (int slot = 0; slot < frame_config->nTddPeriod; ++slot)
for (int sym = 0; sym < 14; ++sym)
sc[slot].nSymbolType[sym] = s7cfg->slot_dirs[slot].sym_dir[sym];
return true;
}
static bool set_fh_ru_config(const paramdef_t *rup, int nru, struct xran_ru_config *ru_config)
{
ru_config->xranTech = XRAN_RAN_5GNR;
ru_config->xranCat = XRAN_CATEGORY_A;
ru_config->xranCompHdrType = XRAN_COMP_HDR_TYPE_STATIC;
ru_config->iqWidth = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH)->uptr;
AssertFatal(ru_config->iqWidth <= 16, "IQ Width cannot be > 16!\n");
ru_config->compMeth = ru_config->iqWidth < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE;
ru_config->iqWidth_PRACH = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH_PRACH)->uptr;
AssertFatal(ru_config->iqWidth_PRACH <= 16, "IQ Width for PRACH cannot be > 16!\n");
ru_config->compMeth_PRACH = ru_config->iqWidth_PRACH < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE;
ru_config->fftSize = *gpd(rup, nru, ORAN_RU_CONFIG_FFT_SIZE)->uptr;
ru_config->byteOrder = XRAN_NE_BE_BYTE_ORDER;
ru_config->iqOrder = XRAN_I_Q_ORDER;
ru_config->xran_max_frame = 0;
return true;
}
static bool set_maxmin_pd(const paramdef_t *pd, int num, const char *name, uint16_t *min, uint16_t *max)
{
const paramdef_t *p = gpd(pd, num, name);
if (p->numelt != 2) {
printf("parameter list \"%s\" should have exactly two parameters (max&min), but has %d\n", name, num);
return false;
}
*min = p->uptr[0];
*max = p->uptr[1];
if (*min > *max) {
printf("min parameter of \"%s\" is larger than max!\n", name);
return false;
}
return true;
}
extern uint32_t to_nrarfcn(int nr_bandP, uint64_t dl_CarrierFreq, uint8_t scs_index, uint32_t bw);
bool set_fh_config(int ru_idx, int num_rus, const openair0_config_t *oai0, struct xran_fh_config *fh_config)
{
AssertFatal(num_rus == 1 || num_rus == 2, "only support 1 or 2 RUs as of now\n");
AssertFatal(ru_idx < num_rus, "illegal ru_idx %d: must be < %d\n", ru_idx, num_rus);
DevAssert(oai0->tx_num_channels > 0 && oai0->rx_num_channels > 0);
DevAssert(oai0->tx_bw > 0 && oai0->rx_bw > 0);
//AssertFatal(oai0->tx_num_channels == oai0->rx_num_channels, "cannot handle unequal number of TX/RX channels\n");
DevAssert(oai0->tx_freq[0] > 0);
for (int i = 1; i < oai0->tx_num_channels; ++i)
DevAssert(oai0->tx_freq[0] == oai0->tx_freq[i]);
DevAssert(oai0->rx_freq[0] > 0);
for (int i = 1; i < oai0->rx_num_channels; ++i)
DevAssert(oai0->rx_freq[0] == oai0->rx_freq[i]);
DevAssert(oai0->nr_band > 0);
DevAssert(oai0->nr_scs_for_raster > 0);
// we simply assume that the loading process provides function to_nrarfcn()
// to calculate the ARFCN numbers from frequency. That is not clean, but the
// best we can do without copy-pasting the function.
uint32_t nDLCenterFreqARFCN = to_nrarfcn(oai0->nr_band, oai0->tx_freq[0], oai0->nr_scs_for_raster, oai0->tx_bw);
uint32_t nULCenterFreqARFCN = to_nrarfcn(oai0->nr_band, oai0->rx_freq[0], oai0->nr_scs_for_raster, oai0->rx_bw);
paramdef_t FHconfigs[] = ORAN_FH_DESC;
paramlist_def_t FH_ConfigList = {CONFIG_STRING_ORAN_FH};
char aprefix[MAX_OPTNAME_SIZE] = {0};
sprintf(aprefix, "%s", CONFIG_STRING_ORAN);
const int nfh = sizeofArray(FHconfigs);
config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix);
if (FH_ConfigList.numelt == 0) {
printf("No configuration section \"%s\" found inside \"%s\": cannot initialize fhi_lib!\n", CONFIG_STRING_ORAN_FH, aprefix);
return false;
}
paramdef_t *fhp = FH_ConfigList.paramarray[ru_idx];
paramdef_t rup[] = ORAN_RU_DESC;
int nru = sizeofArray(rup);
sprintf(aprefix, "%s.%s.[%d].%s", CONFIG_STRING_ORAN, CONFIG_STRING_ORAN_FH, ru_idx, CONFIG_STRING_ORAN_RU);
int ret = config_get(config_get_if(), rup, nru, aprefix);
if (ret < 0) {
printf("No configuration section \"%s\": cannot initialize fhi_lib!\n", aprefix);
return false;
}
paramdef_t prachp[] = ORAN_PRACH_DESC;
int nprach = sizeofArray(prachp);
sprintf(aprefix, "%s.%s.[%d].%s", CONFIG_STRING_ORAN, CONFIG_STRING_ORAN_FH, ru_idx, CONFIG_STRING_ORAN_PRACH);
ret = config_get(config_get_if(), prachp, nprach, aprefix);
if (ret < 0) {
printf("No configuration section \"%s\": cannot initialize fhi_lib!\n", aprefix);
return false;
}
memset(fh_config, 0, sizeof(*fh_config));
fh_config->dpdk_port = ru_idx;
fh_config->sector_id = 0;
fh_config->nCC = 1;
fh_config->neAxc = oai0->tx_num_channels / num_rus;
fh_config->neAxcUl = oai0->rx_num_channels / num_rus;
fh_config->nAntElmTRx = oai0->tx_num_channels / num_rus;
fh_config->nDLFftSize = 0;
fh_config->nULFftSize = 0;
fh_config->nDLRBs = oai0->num_rb_dl;
fh_config->nULRBs = oai0->num_rb_dl;
fh_config->nDLAbsFrePointA = 0;
fh_config->nULAbsFrePointA = 0;
fh_config->nDLCenterFreqARFCN = nDLCenterFreqARFCN;
fh_config->nULCenterFreqARFCN = nULCenterFreqARFCN;
fh_config->ttiCb = NULL;
fh_config->ttiCbParam = NULL;
fh_config->Tadv_cp_dl = *gpd(fhp, nfh, ORAN_FH_CONFIG_TADV_CP_DL)->uptr;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T2A_CP_DL, &fh_config->T2a_min_cp_dl, &fh_config->T2a_max_cp_dl))
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T2A_CP_UL, &fh_config->T2a_min_cp_ul, &fh_config->T2a_max_cp_ul))
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T2A_UP, &fh_config->T2a_min_up, &fh_config->T2a_max_up))
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA3, &fh_config->Ta3_min, &fh_config->Ta3_max))
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_DL, &fh_config->T1a_min_cp_dl, &fh_config->T1a_max_cp_dl))
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_UL, &fh_config->T1a_min_cp_ul, &fh_config->T1a_max_cp_ul))
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_UP, &fh_config->T1a_min_up, &fh_config->T1a_max_up))
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA4, &fh_config->Ta4_min, &fh_config->Ta4_max))
return false;
fh_config->enableCP = 1;
fh_config->prachEnable = 1;
fh_config->srsEnable = 0;
fh_config->puschMaskEnable = 0;
fh_config->puschMaskSlot = 0;
fh_config->cp_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_CP_VLAN_TAG)->uptr;
fh_config->up_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_UP_VLAN_TAG)->uptr;
fh_config->debugStop = 0;
fh_config->debugStopCount = 0;
fh_config->DynamicSectionEna = 0;
fh_config->GPS_Alpha = 0;
fh_config->GPS_Beta = 0;
if (!set_fh_prach_config(oai0, prachp, nprach, &fh_config->prach_conf))
return false;
if (!set_fh_srs_config(&fh_config->srs_conf))
return false;
if (!set_fh_frame_config(oai0, &fh_config->frame_conf))
return false;
if (!set_fh_ru_config(rup, nru, &fh_config->ru_conf))
return false;
fh_config->bbdev_enc = NULL;
fh_config->bbdev_dec = NULL;
// fh_config->tx_cp_eAxC2Vf [not implemented by fhi_lib]
// fh_config->tx_up_eAxC2Vf [not implemented by fhi_lib]
// fh_config->rx_cp_eAxC2Vf [not implemented by fhi_lib]
// fh_config->rx_up_eAxC2Vf [not implemented by fhi_lib]
fh_config->log_level = 1;
fh_config->max_sections_per_slot = 8;
fh_config->max_sections_per_symbol = 8;
return true;
}
+40
View File
@@ -0,0 +1,40 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef ORAN_CONFIG_H
#define ORAN_CONFIG_H
#include "stdbool.h"
#include "stdint.h"
struct xran_fh_init;
void print_fh_init(const struct xran_fh_init *fh_init);
struct xran_fh_config;
void print_fh_config(const struct xran_fh_config *fh_config);
bool set_fh_init(struct xran_fh_init *fh_init);
struct openair0_config;
bool set_fh_config(int ru_idx, int num_rus, const struct openair0_config *oai0_cfg, struct xran_fh_config *fh_config);
// hack to workaround LiteOn limitation
extern int g_kbar;
#endif /* ORAN_CONFIG_H */
+465
View File
@@ -0,0 +1,465 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "xran_fh_o_du.h"
#include "xran_pkt.h"
#include "xran_pkt_up.h"
#include "rte_ether.h"
#include "oran-config.h"
#include "oran-init.h"
#include "oaioran.h"
#include "common/utils/assertions.h"
#include "common_lib.h"
/* PRACH data samples are 32 bits wide (16bits for I/Q). Each packet contains
* 840 samples for long sequence or 144 for short sequence. The payload length
* is 840*16*2/8 octets.*/
#ifdef FCN_1_2_6_EARLIER
#define PRACH_PLAYBACK_BUFFER_BYTES (144 * 4L)
#else
#define PRACH_PLAYBACK_BUFFER_BYTES (840 * 4L)
#endif
// structure holding allocated memory for ports (multiple DUs) and sectors
// (multiple CCs)
static oran_port_instance_t gPortInst[XRAN_PORTS_NUM][XRAN_MAX_SECTOR_NR];
void *gxran_handle;
static uint32_t get_nSW_ToFpga_FTH_TxBufferLen(int mu, int sections)
{
uint32_t xran_max_sections_per_slot = RTE_MAX(sections, XRAN_MIN_SECTIONS_PER_SLOT);
uint32_t overhead = xran_max_sections_per_slot
* (RTE_PKTMBUF_HEADROOM + sizeof(struct rte_ether_hdr) + sizeof(struct xran_ecpri_hdr)
+ sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr));
if (mu <= 1) {
return 13168 + overhead; /* 273*12*4 + 64* + ETH AND ORAN HDRs */
} else if (mu == 3) {
return 3328 + overhead;
} else {
assert(false && "numerology not supported\n");
}
}
static uint32_t get_nFpgaToSW_FTH_RxBufferLen(int mu)
{
/* note: previous code checked MTU:
* mu <= 1: return mtu > XRAN_MTU_DEFAULT ? 13168 : XRAN_MTU_DEFAULT;
* mu == 3: return mtu > XRAN_MTU_DEFAULT ? 3328 : XRAN_MTU_DEFAULT;
* but I don't understand the interest: if the buffer is a big bigger, there
* is no problem, or we could just set the MTU size as buffer size?!
* Go with Max for the moment
*/
if (mu <= 1) {
return 13168; /* 273*12*4 + 64*/
} else if (mu == 3) {
return 3328;
} else {
assert(false && "numerology not supported\n");
}
}
/* is this necessary?
int32_t set_main_core(uint32_t main_core)
{
struct sched_param sched_param;
cpu_set_t cpuset;
int32_t result = 0;
memset(&sched_param, 0, sizeof(struct sched_param));
// set main thread affinity mask to CPU2
sched_param.sched_priority = 99;
CPU_ZERO(&cpuset);
printf("This system has %d processors configured and %d processors available.\n", get_nprocs_conf(), get_nprocs());
if (main_core < get_nprocs_conf())
CPU_SET(main_core, &cpuset);
else
return -1;
if ((result = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset))) {
printf("pthread_setaffinity_np failed: coreId = 2, result = %d\n", result);
}
printf("%s [CPU %2d] [PID: %6d]\n", __FUNCTION__, sched_getcpu(), getpid());
return result;
}
*/
static struct xran_prb_map get_xran_prb_map_dl(const struct xran_fh_config *f)
{
struct xran_prb_map prbmap = {
.dir = XRAN_DIR_DL,
.xran_port = 0,
.band_id = 0,
.cc_id = 0,
.ru_port_id = 0,
.tti_id = 0,
.nPrbElm = 1,
};
struct xran_prb_elm *e = &prbmap.prbMap[0];
e->nStartSymb = 0;
e->numSymb = 14;
e->nRBStart = 0;
e->nRBSize = f->nDLRBs;
e->nBeamIndex = 0;
e->compMethod = f->ru_conf.compMeth;
e->iqWidth = f->ru_conf.iqWidth;
return prbmap;
}
static struct xran_prb_map get_xran_prb_map_ul(const struct xran_fh_config *f)
{
struct xran_prb_map prbmap = {
.dir = XRAN_DIR_UL,
.xran_port = 0,
.band_id = 0,
.cc_id = 0,
.ru_port_id = 0,
.tti_id = 0,
.start_sym_id = 0,
.nPrbElm = 1,
};
struct xran_prb_elm *e = &prbmap.prbMap[0];
e->nStartSymb = 0;
e->numSymb = 14;
e->nRBStart = 0;
e->nRBSize = f->nULRBs;
e->nBeamIndex = 0;
e->compMethod = f->ru_conf.compMeth;
e->iqWidth = f->ru_conf.iqWidth;
return prbmap;
}
static uint32_t oran_allocate_uplane_buffers(
void *instHandle,
struct xran_buffer_list list[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN],
struct xran_flat_buffer buf[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT],
uint32_t ant,
uint32_t bufSize)
{
xran_status_t status;
uint32_t pool;
uint32_t numBufs = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT;
status = xran_bm_init(instHandle, &pool, numBufs, bufSize);
AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status);
printf("xran_bm_init() hInstance %p poolIdx %d elements %d size %d\n", instHandle, pool, numBufs, bufSize);
int count = 0;
for (uint32_t a = 0; a < ant; ++a) {
for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) {
list[a][j].pBuffers = &buf[a][j][0];
for (uint32_t k = 0; k < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++k) {
struct xran_flat_buffer *fb = &list[a][j].pBuffers[k];
fb->nElementLenInBytes = bufSize;
fb->nNumberOfElements = 1;
fb->nOffsetInBytes = 0;
void *ptr;
void *mb;
status = xran_bm_allocate_buffer(instHandle, pool, &ptr, &mb);
AssertFatal(XRAN_STATUS_SUCCESS == status && ptr != NULL && mb != NULL,
"Failed at xran_bm_allocate_buffer(), status %d\n",
status);
count++;
fb->pData = ptr;
fb->pCtrl = mb;
memset(ptr, 0, bufSize);
}
}
}
printf("xran_bm_allocate_buffer() hInstance %p poolIdx %d count %d\n", instHandle, pool, count);
return pool;
}
typedef struct oran_mixed_slot {
uint32_t idx;
uint32_t num_dlsym;
uint32_t num_ulsym;
uint32_t start_ulsym;
} oran_mixed_slot_t;
static oran_mixed_slot_t get_mixed_slot_info(const struct xran_frame_config *fconfig)
{
oran_mixed_slot_t info = {0};
for (size_t sl = 0; sl < fconfig->nTddPeriod; ++sl) {
info.num_dlsym = info.num_ulsym = 0;
for (size_t sym = 0; sym < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++sym) {
uint8_t t = fconfig->sSlotConfig[sl].nSymbolType[sym];
if (t == 0 /* DL */) {
info.num_dlsym++;
} else if (t == 1 /* UL */) {
if (info.num_ulsym == 0)
info.start_ulsym = sym;
info.num_ulsym++;
} else if (t == 2 /* Mixed */) {
info.idx = sl;
} else {
AssertFatal(false, "unknown symbol type %d\n", t);
}
}
if (info.idx > 0)
return info;
}
AssertFatal(false, "could not find mixed slot!\n");
return info;
}
typedef struct oran_cplane_prb_config {
uint8_t nTddPeriod;
uint32_t mixed_slot_index;
struct xran_prb_map slotMap;
struct xran_prb_map mixedSlotMap;
} oran_cplane_prb_config;
static void oran_allocate_cplane_buffers(void *instHandle,
struct xran_buffer_list list[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN],
struct xran_flat_buffer buf[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN],
uint32_t ant,
uint32_t sect,
uint32_t size_of_prb_map,
const oran_cplane_prb_config *prb_conf)
{
xran_status_t status;
uint32_t poolSec;
uint32_t numBufsSec = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT * sect * XRAN_MAX_FRAGMENT;
uint32_t bufSizeSec = sizeof(struct xran_section_desc);
status = xran_bm_init(instHandle, &poolSec, numBufsSec, bufSizeSec);
AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status);
printf("xran_bm_init() hInstance %p poolIdx %d elements %d size %d\n", instHandle, poolSec, numBufsSec, bufSizeSec);
uint32_t poolPrb;
uint32_t numBufsPrb = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT;
uint32_t bufSizePrb = size_of_prb_map;
status = xran_bm_init(instHandle, &poolPrb, numBufsPrb, bufSizePrb);
AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status);
printf("xran_bm_init() hInstance %p poolIdx %d elements %d size %d\n", instHandle, poolPrb, numBufsPrb, bufSizePrb);
uint32_t count1 = 0;
uint32_t count2 = 0;
for (uint32_t a = 0; a < ant; a++) {
for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) {
list[a][j].pBuffers = &buf[a][j];
struct xran_flat_buffer *fb = list[a][j].pBuffers;
fb->nElementLenInBytes = bufSizePrb;
fb->nNumberOfElements = 1;
fb->nOffsetInBytes = 0;
void *ptr;
void *mb;
status = xran_bm_allocate_buffer(instHandle, poolPrb, &ptr, &mb);
AssertFatal(XRAN_STATUS_SUCCESS == status && ptr != NULL && mb != NULL,
"Failed at xran_bm_allocate_buffer(), status %d\n",
status);
count1++;
fb->pData = ptr;
fb->pCtrl = mb;
// the original sample app code copies up to size_of_prb_map, but I think
// this is wrong because the way it is computed leads to a number larger
// than sizeof(map)
struct xran_prb_map *p_rb_map = (struct xran_prb_map *)ptr;
const struct xran_prb_map *src = &prb_conf->slotMap;
if ((j % prb_conf->nTddPeriod) == prb_conf->mixed_slot_index)
src = &prb_conf->mixedSlotMap;
memcpy(p_rb_map, src, sizeof(*src));
for (uint32_t elm_id = 0; elm_id < p_rb_map->nPrbElm; ++elm_id) {
struct xran_prb_elm *pPrbElem = &p_rb_map->prbMap[elm_id];
for (uint32_t k = 0; k < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++k) {
for (uint32_t m = 0; m < XRAN_MAX_FRAGMENT; ++m) {
void *sd_ptr;
void *sd_mb;
status = xran_bm_allocate_buffer(instHandle, poolSec, &sd_ptr, &sd_mb);
AssertFatal(XRAN_STATUS_SUCCESS == status,
"Failed at xran_bm_allocate_buffer(), status %d m %d k %d elm_id %d\n",
status,
m,
k,
elm_id);
count2++;
pPrbElem->p_sec_desc[k][m] = sd_ptr;
memset(sd_ptr, 0, sizeof(struct xran_section_desc));
}
}
}
}
}
printf("xran_bm_allocate_buffer() hInstance %p poolIdx %d count %d\n", instHandle, poolPrb, count1);
printf("xran_bm_allocate_buffer() hInstance %p poolIdx %d count %d\n", instHandle, poolSec, count2);
}
/* callback not actively used */
static void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status)
{
rte_pause();
}
static void oran_allocate_buffers(void *handle,
int xran_inst,
int num_sectors,
oran_port_instance_t *portInstances,
const struct xran_fh_config *fh_config)
{
AssertFatal(num_sectors == 1, "only support one sector at the moment\n");
oran_port_instance_t *pi = &portInstances[0];
AssertFatal(handle != NULL, "no handle provided\n");
uint32_t xran_max_antenna_nr = RTE_MAX(fh_config->neAxc, fh_config->neAxcUl);
uint32_t xran_max_sections_per_slot = RTE_MAX(fh_config->max_sections_per_slot, XRAN_MIN_SECTIONS_PER_SLOT);
uint32_t size_of_prb_map = sizeof(struct xran_prb_map) + sizeof(struct xran_prb_elm) * (xran_max_sections_per_slot - 1);
pi->buf_list = _mm_malloc(sizeof(*pi->buf_list), 256);
AssertFatal(pi->buf_list != NULL, "out of memory\n");
oran_buf_list_t *bl = pi->buf_list;
xran_status_t status;
printf("xran_sector_get_instances() o_xu_id %d xran_handle %p\n", xran_inst, handle);
status = xran_sector_get_instances(xran_inst, handle, num_sectors, &pi->instanceHandle);
printf("-> hInstance %p\n", pi->instanceHandle);
AssertFatal(status == XRAN_STATUS_SUCCESS, "get sector instance failed for XRAN nInstanceNum %d\n", xran_inst);
const uint32_t txBufSize = get_nSW_ToFpga_FTH_TxBufferLen(fh_config->frame_conf.nNumerology, fh_config->max_sections_per_slot);
oran_allocate_uplane_buffers(pi->instanceHandle, bl->src, bl->bufs.tx, xran_max_antenna_nr, txBufSize);
oran_mixed_slot_t info = get_mixed_slot_info(&fh_config->frame_conf);
struct xran_prb_map dlPm = get_xran_prb_map_dl(fh_config);
struct xran_prb_map dlPmMixed = dlPm;
dlPmMixed.prbMap[0].nStartSymb = 0;
dlPmMixed.prbMap[0].numSymb = info.num_dlsym;
oran_cplane_prb_config dlConf = {
.nTddPeriod = fh_config->frame_conf.nTddPeriod,
.mixed_slot_index = info.idx,
.slotMap = dlPm,
.mixedSlotMap = dlPmMixed,
};
oran_allocate_cplane_buffers(pi->instanceHandle,
bl->srccp,
bl->bufs.tx_prbmap,
xran_max_antenna_nr,
xran_max_sections_per_slot,
size_of_prb_map,
&dlConf);
const uint32_t rxBufSize = get_nFpgaToSW_FTH_RxBufferLen(fh_config->frame_conf.nNumerology);
oran_allocate_uplane_buffers(pi->instanceHandle, bl->dst, bl->bufs.rx, xran_max_antenna_nr, rxBufSize);
struct xran_prb_map ulPm = get_xran_prb_map_ul(fh_config);
struct xran_prb_map ulPmMixed = ulPm;
ulPmMixed.prbMap[0].nStartSymb = info.start_ulsym;
ulPmMixed.prbMap[0].numSymb = info.num_ulsym;
oran_cplane_prb_config ulConf = {
.nTddPeriod = fh_config->frame_conf.nTddPeriod,
.mixed_slot_index = info.idx,
.slotMap = ulPm,
.mixedSlotMap = ulPmMixed,
};
oran_allocate_cplane_buffers(pi->instanceHandle,
bl->dstcp,
bl->bufs.rx_prbmap,
xran_max_antenna_nr,
xran_max_sections_per_slot,
size_of_prb_map,
&ulConf);
// PRACH
const uint32_t prachBufSize = PRACH_PLAYBACK_BUFFER_BYTES;
oran_allocate_uplane_buffers(pi->instanceHandle, bl->prachdst, bl->bufs.prach, xran_max_antenna_nr, prachBufSize);
// PRACH decomp buffer does not have separate DPDK-allocated memory pool
// bufs, it points to the same pool as the prach buffer. Unclear to me why
for (uint32_t a = 0; a < xran_max_antenna_nr; ++a) {
for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) {
bl->prachdstdecomp[a][j].pBuffers = &bl->bufs.prachdecomp[a][j][0];
for (uint32_t k = 0; k < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++k) {
struct xran_flat_buffer *fb = &bl->prachdstdecomp[a][j].pBuffers[k];
fb->pData = bl->prachdst[a][j].pBuffers[k].pData;
}
}
}
struct xran_buffer_list *src[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *srccp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *dst[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *dstcp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *prach[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *prachdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
for (uint32_t a = 0; a < XRAN_MAX_ANTENNA_NR; ++a) {
for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) {
src[a][j] = &bl->src[a][j];
srccp[a][j] = &bl->srccp[a][j];
dst[a][j] = &bl->dst[a][j];
dstcp[a][j] = &bl->dstcp[a][j];
prach[a][j] = &bl->prachdst[a][j];
prachdecomp[a][j] = &bl->prachdstdecomp[a][j];
}
}
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->RxCbTag[0][0]);
xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->PrachCbTag[0][0]);
}
int *oai_oran_initialize(const openair0_config_t *openair0_cfg)
{
int32_t xret = 0;
struct xran_fh_init init = {0};
if (!set_fh_init(&init)) {
printf("could not read FHI 7.2/ORAN config\n");
return NULL;
}
print_fh_init(&init);
/* read all configuration before starting anything */
struct xran_fh_config xran_fh_config[XRAN_PORTS_NUM] = {0};
for (int32_t o_xu_id = 0; o_xu_id < init.xran_ports; o_xu_id++) {
if (!set_fh_config(o_xu_id, init.xran_ports, openair0_cfg, &xran_fh_config[o_xu_id])) {
printf("could not read FHI 7.2/RU-specific config\n");
return NULL;
}
print_fh_config(&xran_fh_config[o_xu_id]);
}
// if ((xret = set_main_core(init.something)) < 0) {
// printf("set_main_core() failed %d\n", xret);
// exit(-1);
// }
xret = xran_init(0, NULL, &init, NULL, &gxran_handle);
if (xret != XRAN_STATUS_SUCCESS) {
printf("xran_init failed %d\n", xret);
exit(-1);
}
/** process all the O-RU|O-DU for use case */
for (int32_t o_xu_id = 0; o_xu_id < init.xran_ports; o_xu_id++) {
xret = xran_open(gxran_handle, &xran_fh_config[o_xu_id]);
if (xret != XRAN_STATUS_SUCCESS) {
printf("xran_open failed %d\n", xret);
exit(-1);
}
int sector = 0;
oran_port_instance_t *pi = &gPortInst[o_xu_id][sector];
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]);
if ((xret = xran_reg_physide_cb(gxran_handle, oai_physide_dl_tti_call_back, NULL, 10, XRAN_CB_TTI)) != XRAN_STATUS_SUCCESS) {
printf("xran_reg_physide_cb failed %d\n", xret);
exit(-1);
}
}
return (void *)gxran_handle;
}
+63
View File
@@ -0,0 +1,63 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef ORAN_INIT_H
#define ORAN_INIT_H
typedef struct oran_bufs {
struct xran_flat_buffer tx[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT];
struct xran_flat_buffer tx_prbmap[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_flat_buffer rx[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT];
struct xran_flat_buffer rx_prbmap[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_flat_buffer prach[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT];
struct xran_flat_buffer prachdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT];
} oran_bufs_t;
typedef struct oran_buf_list {
// xran API requires buffer lists as structs of arrays
struct xran_buffer_list src[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list srccp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list dst[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list dstcp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list prachdst[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list prachdstdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
oran_bufs_t bufs;
} oran_buf_list_t;
typedef struct oran_port_instance_t {
oran_buf_list_t *buf_list;
void *instanceHandle;
//uint32_t dpdkPoolIndex[MAX_SW_XRAN_INTERFACE_NUM];
struct xran_cb_tag RxCbTag[XRAN_PORTS_NUM][XRAN_MAX_SECTOR_NR];
struct xran_cb_tag PrachCbTag[XRAN_PORTS_NUM][XRAN_MAX_SECTOR_NR];
} oran_port_instance_t;
extern struct xran_fh_config gxran_fh_config[XRAN_PORTS_NUM];
extern void *gxran_handle;
struct openair0_config;
int *oai_oran_initialize(const struct openair0_config *openair0_cfg);
#endif /* ORAN_INIT_H */
+114
View File
@@ -0,0 +1,114 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef ORAN_PARAMS_H
#define ORAN_PARAMS_H
#include "stdbool.h"
#include "stdint.h"
#define CONFIG_STRING_ORAN "fhi_72"
#define ORAN_CONFIG_DPDK_DEVICES "dpdk_devices"
#define ORAN_CONFIG_IO_CORE "io_core"
#define ORAN_CONFIG_WORKER_CORES "worker_cores"
#define ORAN_CONFIG_DU_ADDR "du_addr"
#define ORAN_CONFIG_RU_ADDR "ru_addr"
#define ORAN_CONFIG_MTU "mtu"
#define ORAN_CONFIG_FILE_PREFIX "file_prefix"
#define ORAN_CONFIG_NETHPERPORT "eth_lines"
#define ORAN_CONFIG_NETHSPEED "eth_speed"
// clang-format off
// TODO: PCI addr check
// TODO: ethernet addr check
#define ORAN_GLOBALPARAMS_DESC { \
{ORAN_CONFIG_DPDK_DEVICES, "PCI addr of devices for DPDK\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_IO_CORE, "DPDK Core used for IO\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=4, TYPE_INT, 0}, \
{ORAN_CONFIG_WORKER_CORES, "CPU Cores to use for workers\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=NULL,TYPE_UINTARRAY, 0}, \
{ORAN_CONFIG_DU_ADDR, "Ether addr of DU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_RU_ADDR, "Ether addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_MTU, "MTU of Eth interface\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=1500, TYPE_UINT, 0}, \
{ORAN_CONFIG_FILE_PREFIX, "DPDK file-prefix\n", 0, .strptr=NULL, .defstrval="wls_0", TYPE_STRING, 0}, \
{ORAN_CONFIG_NETHPERPORT, "number of links per port\n", 0, .uptr=NULL, .defuintval=1, TYPE_UINT, 0}, \
{ORAN_CONFIG_NETHSPEED, "ethernet speed link\n", 0, .uptr=NULL, .defuintval=10, TYPE_UINT, 0}, \
}
// clang-format on
#define CONFIG_STRING_ORAN_FH "fh_config"
#define ORAN_FH_CONFIG_TADV_CP_DL "Tadv_cp_dl"
#define ORAN_FH_CONFIG_T2A_CP_DL "T2a_cp_dl"
#define ORAN_FH_CONFIG_T2A_CP_UL "T2a_cp_ul"
#define ORAN_FH_CONFIG_T2A_UP "T2a_up"
#define ORAN_FH_CONFIG_TA3 "Ta3"
#define ORAN_FH_CONFIG_T1A_CP_DL "T1a_cp_dl"
#define ORAN_FH_CONFIG_T1A_CP_UL "T1a_cp_ul"
#define ORAN_FH_CONFIG_T1A_UP "T1a_up"
#define ORAN_FH_CONFIG_TA4 "Ta4"
#define ORAN_FH_CONFIG_CP_VLAN_TAG "cp_vlan_tag"
#define ORAN_FH_CONFIG_UP_VLAN_TAG "up_vlan_tag"
#define ORAN_FH_HLP_CPLT " parameter of RU in list form (Min&Max, length 2!)\n"
// clang-format off
#define ORAN_FH_DESC { \
{ORAN_FH_CONFIG_TADV_CP_DL, "Tadv parameter of RU\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
{ORAN_FH_CONFIG_T2A_CP_DL, "T2a_cp_dl" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_T2A_CP_UL, "T2a_cp_ul" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_T2A_UP, "T2a_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_TA3, "Ta3" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_T1A_CP_DL, "T1a_cp_dl" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_T1A_CP_UL, "T1a_cp_ul" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_T1A_UP, "T1a_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_TA4, "Ta4" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_CP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
{ORAN_FH_CONFIG_UP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
}
// clang-format on
#define CONFIG_STRING_ORAN_RU "ru_config"
#define ORAN_RU_CONFIG_IQWIDTH "iq_width"
#define ORAN_RU_CONFIG_IQWIDTH_PRACH "iq_width_prach"
#define ORAN_RU_CONFIG_FFT_SIZE "fft_size"
// clang-format off
#define ORAN_RU_DESC {\
{ORAN_RU_CONFIG_IQWIDTH, "sample IQ width (16=uncompressed)\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=16, TYPE_UINT8, 0}, \
{ORAN_RU_CONFIG_IQWIDTH_PRACH, "PRACH sample IQ width (16=uncompressed)\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=16, TYPE_UINT8, 0}, \
{ORAN_RU_CONFIG_FFT_SIZE, "Size of FFT at RU\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=12, TYPE_UINT8, 0}, \
}
// clang-format on
#define CONFIG_STRING_ORAN_PRACH "prach_config"
#define ORAN_PRACH_CONFIG_EAXC_OFFSET "eAxC_offset"
#define ORAN_PRACH_CONFIG_KBAR "kbar"
// clang-format off
#define ORAN_PRACH_DESC {\
{ORAN_PRACH_CONFIG_EAXC_OFFSET, "RU's eAxC offset for PRACH\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=0, TYPE_UINT8, 0}, \
{ORAN_PRACH_CONFIG_KBAR, "PRACH guard interval\n", 0, .uptr=NULL, .defuintval=4, TYPE_UINT, 0}, \
}
// clang-format on
#endif /* ORAN_PARAMS_H */
+40
View File
@@ -0,0 +1,40 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef _ORAN_H_
#define _ORAN_H_
#include "shared_buffers.h"
#include "common_lib.h"
void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp);
void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot);
int transport_init(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
typedef struct {
eth_state_t e;
shared_buffers buffers;
rru_config_msg_type_t last_msg;
int capabilities_sent;
void *oran_priv;
} oran_eth_state_t;
#endif /* _ORAN_H_ */
+318
View File
@@ -0,0 +1,318 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <stdio.h>
#include <string.h>
#include "common_lib.h"
#include "radio/ETHERNET/ethernet_lib.h"
#include "oran_isolate.h"
#include "oran-init.h"
#include "xran_fh_o_du.h"
#include "xran_sync_api.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "openair1/PHY/defs_gNB.h"
#include "common/utils/threadPool/thread-pool.h"
#include "oaioran.h"
typedef struct {
eth_state_t e;
rru_config_msg_type_t last_msg;
int capabilities_sent;
void *oran_priv;
} oran_eth_state_t;
notifiedFIFO_t oran_sync_fifo;
int trx_oran_start(openair0_device *device)
{
printf("ORAN: %s\n", __FUNCTION__);
oran_eth_state_t *s = device->priv;
// Start ORAN
if (xran_start(s->oran_priv) != 0) {
printf("%s:%d:%s: Start ORAN failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__);
exit(1);
} else {
printf("Start ORAN. Done\n");
}
return 0;
}
void trx_oran_end(openair0_device *device)
{
printf("ORAN: %s\n", __FUNCTION__);
oran_eth_state_t *s = device->priv;
xran_close(s->oran_priv);
}
int trx_oran_stop(openair0_device *device)
{
printf("ORAN: %s\n", __FUNCTION__);
oran_eth_state_t *s = device->priv;
xran_stop(s->oran_priv);
return (0);
}
int trx_oran_set_freq(openair0_device *device, openair0_config_t *openair0_cfg)
{
printf("ORAN: %s\n", __FUNCTION__);
return (0);
}
int trx_oran_set_gains(openair0_device *device, openair0_config_t *openair0_cfg)
{
printf("ORAN: %s\n", __FUNCTION__);
return (0);
}
int trx_oran_get_stats(openair0_device *device)
{
printf("ORAN: %s\n", __FUNCTION__);
return (0);
}
int trx_oran_reset_stats(openair0_device *device)
{
printf("ORAN: %s\n", __FUNCTION__);
return (0);
}
int ethernet_tune(openair0_device *device, unsigned int option, int value)
{
printf("ORAN: %s\n", __FUNCTION__);
return 0;
}
int trx_oran_write_raw(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags)
{
printf("ORAN: %s\n", __FUNCTION__);
return 0;
}
int trx_oran_read_raw(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc)
{
printf("ORAN: %s\n", __FUNCTION__);
return 0;
}
char *msg_type(int t)
{
static char *s[12] = {
"RAU_tick",
"RRU_capabilities",
"RRU_config",
"RRU_config_ok",
"RRU_start",
"RRU_stop",
"RRU_sync_ok",
"RRU_frame_resynch",
"RRU_MSG_max_num",
"RRU_check_sync",
"RRU_config_update",
"RRU_config_update_ok",
};
if (t < 0 || t > 11)
return "UNKNOWN";
return s[t];
}
int trx_oran_ctlsend(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
oran_eth_state_t *s = device->priv;
printf("ORAN: %s\n", __FUNCTION__);
printf(" rru_config_msg->type %d [%s]\n", rru_config_msg->type, msg_type(rru_config_msg->type));
s->last_msg = rru_config_msg->type;
return msg_len;
}
int trx_oran_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
oran_eth_state_t *s = device->priv;
printf("ORAN: %s\n", __FUNCTION__);
if (s->last_msg == RAU_tick && s->capabilities_sent == 0) {
printf("ORAN ctrlrcv RRU_tick received and send capabilities hard coded\n");
RRU_capabilities_t *cap;
rru_config_msg->type = RRU_capabilities;
rru_config_msg->len = sizeof(RRU_CONFIG_msg_t) - MAX_RRU_CONFIG_SIZE + sizeof(RRU_capabilities_t);
// Fill RRU capabilities (see openair1/PHY/defs_RU.h)
// For now they are hard coded - try to retreive the params from openari device
cap = (RRU_capabilities_t *)&rru_config_msg->msg[0];
cap->FH_fmt = OAI_IF4p5_only;
cap->num_bands = 1;
cap->band_list[0] = 78;
// cap->num_concurrent_bands = 1; component carriers
cap->nb_rx[0] = 1; // device->openair0_cfg->rx_num_channels;
cap->nb_tx[0] = 1; // device->openair0_cfg->tx_num_channels;
cap->max_pdschReferenceSignalPower[0] = -27;
cap->max_rxgain[0] = 90;
cap->N_RB_DL[0] = 106;
cap->N_RB_UL[0] = 106;
s->capabilities_sent = 1;
return rru_config_msg->len;
}
if (s->last_msg == RRU_config) {
printf("Oran RRU_config\n");
rru_config_msg->type = RRU_config_ok;
}
return 0;
}
void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
{
ru_info_t ru_info;
ru_info.nb_rx = ru->nb_rx;
ru_info.rxdataF = ru->common.rxdataF;
ru_info.prach_buf = ru->prach_rxsigF[0]; // index: [prach_oca][ant_id]
RU_proc_t *proc = &ru->proc;
extern uint16_t sl_ahead;
int f, sl;
LOG_D(PHY, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]);
start_meas(&ru->rx_fhaul);
int ret = xran_fh_rx_read_slot(&ru_info, &f, &sl);
stop_meas(&ru->rx_fhaul);
LOG_D(PHY, "Read %d.%d rxdataF %p,%p\n", f, sl, ru_info.rxdataF[0], ru_info.rxdataF[1]);
if (ret != 0) {
printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX function \n", f, sl);
}
proc->tti_rx = sl;
proc->frame_rx = f;
proc->tti_tx = (sl + sl_ahead) % 20;
proc->frame_tx = (sl > (19 - sl_ahead)) ? (f + 1) & 1023 : f;
if (proc->first_rx == 0) {
if (proc->tti_rx != *slot) {
LOG_E(PHY,
"Received Time doesn't correspond to the time we think it is (slot mismatch, received %d.%d, expected %d.%d)\n",
proc->frame_rx,
proc->tti_rx,
*frame,
*slot);
*slot = proc->tti_rx;
}
if (proc->frame_rx != *frame) {
LOG_E(PHY,
"Received Time doesn't correspond to the time we think it is (frame mismatch, %d.%d , expected %d.%d)\n",
proc->frame_rx,
proc->tti_rx,
*frame,
*slot);
*frame = proc->frame_rx;
}
} else {
proc->first_rx = 0;
LOG_I(PHY, "before adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx);
*frame = proc->frame_rx;
*slot = proc->tti_rx;
LOG_I(PHY, "After adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx);
}
}
void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp)
{
start_meas(&ru->tx_fhaul);
ru_info_t ru_info;
ru_info.nb_tx = ru->nb_tx;
ru_info.txdataF_BF = ru->common.txdataF_BF;
// printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp);
int ret = xran_fh_tx_send_slot(&ru_info, frame, slot, timestamp);
if (ret != 0) {
printf("ORAN: ORAN_fh_if4p5_south_out ERROR in TX function \n");
}
stop_meas(&ru->tx_fhaul);
}
void *get_internal_parameter(char *name)
{
printf("ORAN: %s\n", __FUNCTION__);
if (!strcmp(name, "fh_if4p5_south_in"))
return (void *)oran_fh_if4p5_south_in;
if (!strcmp(name, "fh_if4p5_south_out"))
return (void *)oran_fh_if4p5_south_out;
return NULL;
}
__attribute__((__visibility__("default"))) int transport_init(openair0_device *device,
openair0_config_t *openair0_cfg,
eth_params_t *eth_params)
{
oran_eth_state_t *eth;
device->Mod_id = 0;
device->transp_type = ETHERNET_TP;
device->trx_start_func = trx_oran_start;
device->trx_get_stats_func = trx_oran_get_stats;
device->trx_reset_stats_func = trx_oran_reset_stats;
device->trx_end_func = trx_oran_end;
device->trx_stop_func = trx_oran_stop;
device->trx_set_freq_func = trx_oran_set_freq;
device->trx_set_gains_func = trx_oran_set_gains;
device->trx_write_func = trx_oran_write_raw;
device->trx_read_func = trx_oran_read_raw;
device->trx_ctlsend_func = trx_oran_ctlsend;
device->trx_ctlrecv_func = trx_oran_ctlrecv;
device->get_internal_parameter = get_internal_parameter;
eth = (oran_eth_state_t *)calloc(1, sizeof(oran_eth_state_t));
if (eth == NULL) {
AssertFatal(0 == 1, "out of memory\n");
}
eth->e.flags = ETH_RAW_IF4p5_MODE;
eth->e.compression = NO_COMPRESS;
eth->e.if_name = eth_params->local_if_name;
eth->oran_priv = NULL; // define_oran_pointer();
device->priv = eth;
device->openair0_cfg = &openair0_cfg[0];
eth->last_msg = (rru_config_msg_type_t)-1;
printf("ORAN: %s\n", __FUNCTION__);
initNotifiedFIFO(&oran_sync_fifo);
eth->oran_priv = oai_oran_initialize(openair0_cfg);
AssertFatal(eth->oran_priv != NULL, "can not initialize fronthaul");
// create message queues for ORAN sync
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef _ORAN_ISOLATE_H_
#define _ORAN_ISOLATE_H_
#include <stdio.h>
#include <pthread.h>
#include <stdint.h>
#include "xran_fh_o_du.h"
/*
* Structure added to bear the information needed from OAI RU
*/
typedef struct ru_info_s {
// Needed for UL
int nb_rx;
int32_t **rxdataF;
// Needed for DL
int nb_tx;
int32_t **txdataF_BF;
// Needed for Prach
int16_t **prach_buf;
} ru_info_t;
int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot);
int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp);
int compute_xran_statistics();
#endif /* _ORAN_ISOLATE_H_ */